Changeset 77 for trunk/src/os2ahci/os2ahci.c
- Timestamp:
- Feb 22, 2011, 2:25:44 AM (14 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/os2ahci/os2ahci.c
r76 r77 41 41 } 42 42 43 /* set two-dimensional array of port options */ 44 #define set_port_option(opt, val) \ 45 if (adapter_index == -1) { \ 46 /* set option for all adapters and ports */ \ 47 memset(opt, val, sizeof(opt)); \ 48 } else if (port_index == -1) { \ 49 /* set option for all ports on current adapter */ \ 50 memset(opt[adapter_index], val, sizeof(*opt)); \ 51 } else { \ 52 /* set option for specific port */ \ 53 opt[adapter_index][port_index] = val; \ 54 } 55 43 56 /* ------------------------ typedefs and structures ------------------------ */ 44 57 45 58 /* -------------------------- function prototypes -------------------------- */ 46 59 47 void _cdecl small_code_ (void); 60 void _cdecl small_code_ (void); 61 62 static int add_unit_info (IORB_CONFIGURATION _far *iorb_conf, int dt_ai, 63 int a, int p, int d, int scsi_id); 48 64 49 65 /* ------------------------ global/static variables ------------------------ */ 50 66 51 67 int debug = 0; /* if > 0, print debug messages to COM1 */ 52 int thorough_scan ;/* if != 0, perform thorough PCI scan */68 int thorough_scan = 1; /* if != 0, perform thorough PCI scan */ 53 69 int init_reset; /* if != 0, reset ports during init */ 54 70 … … 84 100 85 101 /* apapter/port-specific options saved when parsing the command line */ 102 u8 emulate_scsi[MAX_AD][AHCI_MAX_PORTS]; 103 u8 disable_ncq[MAX_AD][AHCI_MAX_PORTS]; 86 104 u8 link_speed[MAX_AD][AHCI_MAX_PORTS]; 87 u8 disable_ncq[MAX_AD][AHCI_MAX_PORTS];105 u8 link_power[MAX_AD][AHCI_MAX_PORTS]; 88 106 89 107 static char init_msg[] = "OS2AHCI driver version %d.%02d\n"; … … 91 109 static char eval_msg[] = ANSI_CLR_RED ANSI_CLR_BRIGHT "Evaluation version " 92 110 "- not licensed for production use.\n" ANSI_RESET; 93 94 111 95 112 /* ----------------------------- start of code ----------------------------- */ … … 139 156 int adapter_index = -1; 140 157 int port_index = -1; 158 int invert_option; 159 int optval; 141 160 u16 vendor; 142 161 u16 device; … … 148 167 DevHelp_CreateSpinLock(&drv_lock); 149 168 150 if (debug) { 151 /* initialize debug interface (COM1) */ 152 init_com1(); 153 } 169 /* initialize libc code */ 170 init_libc(); 154 171 155 172 /* print initialization message */ … … 167 184 168 185 for (s = cmd_line; *s != 0; s++) { 169 if (*s == '/' && s[1] != '\0') { 186 if (*s == '/') { 187 if ((invert_option = (s[1] == '!')) != 0) { 188 s++; 189 } 170 190 s++; 171 switch(tolower(*s)) { 191 switch (tolower(*s)) { 192 193 case '\0': 194 /* end of command line; can only happen if command line is incorrect */ 195 cprintf("incomplete command line option\n"); 196 goto init_fail; 172 197 173 198 case 'c': … … 178 203 case 'd': 179 204 /* increase debug level */ 180 debug++; 205 if (debug++ == 0) { 206 init_com(); 207 } 181 208 break; 182 209 … … 194 221 case 't': 195 222 /* perform thorough PCI scan (i.e. look for individual supported PCI IDs) */ 196 thorough_scan = 1;223 thorough_scan = !invert_option; 197 224 break; 198 225 … … 200 227 /* reset ports during initialization */ 201 228 init_reset = 1; 202 break;203 204 case 'i':205 /* ignore current adapter index */206 if (adapter_index >= 0) {207 ad_ignore |= 1U << adapter_index;208 }209 229 break; 210 230 … … 227 247 break; 228 248 249 case 'i': 250 /* ignore current adapter index */ 251 if (adapter_index >= 0) { 252 ad_ignore |= 1U << adapter_index; 253 } 254 break; 255 229 256 case 's': 230 /* set link speed of current port on current adapter */ 231 drv_parm_int(s, link_speed[adapter_index][port_index], u8, 10); 232 init_reset = 1; 257 /* enable SCSI emulation for ATAPI devices */ 258 set_port_option(emulate_scsi, !invert_option); 233 259 break; 234 260 235 261 case 'n': 236 262 /* disable NCQ */ 237 if (adapter_index == -1) { 238 /* disable NCQ on all adapters and ports */ 239 memset(disable_ncq, 0x01, sizeof(disable_ncq)); 240 } else if (port_index == -1) { 241 /* disable NCQ on all ports of this adapter */ 242 memset(disable_ncq[adapter_index], 0x01, sizeof(*disable_ncq)); 243 } else { 244 /* disable NCQ for this adapter and port */ 245 disable_ncq[adapter_index][port_index] = 1; 246 } 263 set_port_option(disable_ncq, !invert_option); 264 break; 265 266 case 'l': 267 /* set link speed or power savings */ 268 s++; 269 switch (tolower(*s)) { 270 case 's': 271 /* set link speed */ 272 drv_parm_int(s, optval, int, 10); 273 set_port_option(link_speed, optval); 274 break; 275 case 'p': 276 /* set power management */ 277 drv_parm_int(s, optval, int, 10); 278 set_port_option(link_power, optval); 279 break; 280 default: 281 cprintf("invalid link parameter (%c)\n", *s); 282 goto init_fail; 283 } 284 /* need to reset the port in order to establish link settings */ 285 init_reset = 1; 247 286 break; 248 287 … … 402 441 iorb->Status = IORB_ERROR; 403 442 iorb->ErrorCode = IOERR_CMD_SYNTAX; 404 complete_iorb(iorb);443 iorb_complete(iorb); 405 444 continue; 406 445 } … … 744 783 * Scan all ports for AHCI devices and construct a DASD device table. 745 784 * 746 * NOTE: This function may be called multiple times. Only the first invocation 747 * will actually scan for devices; all subsequent calls will merely 748 * return the results of the initial scan, potentially augmented by 749 * modified unit infos after IOCC_CONFIGURATION/IOCM_CHANGE_UNITINFO 750 * requests. 785 * NOTES: This function may be called multiple times. Only the first 786 * invocation will actually scan for devices; all subsequent calls will 787 * merely return the results of the initial scan, potentially augmented 788 * by modified unit infos after IOCC_CONFIGURATION/IOCM_CHANGE_UNITINFO 789 * requests. 790 * 791 * In order to support applications that can't deal with ATAPI devies 792 * (i.e. need a SCSI adapter) os2ahci will optionally report ATAPI 793 * dvices as SCSI devices. The corresponding SCSI adapter doesn't 794 * really exist and is only reported here for the IOCM_GET_DEVICETABLE 795 * request. The units attached to this adapter will use the real HW 796 * unit IDs, thus we'll never receive a command specific to the 797 * emulated SCSI adapter and won't need to set up any sort of entity 798 * for it; the only purpose of the emulated SCSI adapter is to pass the 799 * bus type "AI_DEVBUS_SCSI_2" upstream, and the emulated units, of 800 * course. The emulated SCSI target IDs are allocated as follows: 801 * 802 * 0 the virtual adapter 803 * 1..n emulated devices; SCSI target ID increments sequentially 751 804 */ 752 805 void iocm_device_table(IORBH _far *iorb) … … 755 808 DEVICETABLE _far *dt; 756 809 char _far *pos; 810 int scsi_units = 0; 811 int scsi_id = 1; 757 812 int rc; 813 int dta; 758 814 int a; 759 815 int p; … … 769 825 dt->ADDLevelMinor = ADD_LEVEL_MINOR; 770 826 dt->ADDHandle = add_handle; 771 dt->TotalAdapters = ad_info_cnt; 772 773 /* Initial position of dynamic portion of device table (i.e. behind the 774 * array of ADAPTERINFO pointers, pAdapter, in the device table) 775 */ 776 pos = (char _far *) (dt->pAdapter + ad_info_cnt); 777 778 for (a = 0; a < ad_info_cnt; a++) { 827 dt->TotalAdapters = ad_info_cnt + 1; 828 829 /* set start of adapter and device information tables */ 830 pos = (char _far *) (dt->pAdapter + dt->TotalAdapters); 831 832 /* go through all adapters, including the virtual SCSI adapter */ 833 for (dta = 0; dta < dt->TotalAdapters; dta++) { 779 834 ADAPTERINFO _far *ptr = (ADAPTERINFO _far *) pos; 780 AD_INFO *ad_info = ad_infos + a;781 int units = 0;782 835 783 836 /* sanity check for sufficient space in device table */ … … 788 841 } 789 842 790 /* set ADAPTERINFO offset in device table */ 791 dt->pAdapter[a] = (ADAPTERINFO _near *) ((u32) ptr & 0xffff); 792 793 /* fill in adapter information structure in device table */ 843 dt->pAdapter[dta] = (ADAPTERINFO _near *) ((u32) ptr & 0xffff); 794 844 memset(ptr, 0x00, sizeof(*ptr)); 795 sprintf(ptr->AdapterName, "AHCI_%d", a); 796 ptr->AdapterDevBus = AI_DEVBUS_ST506 | AI_DEVBUS_32BIT; 845 797 846 ptr->AdapterIOAccess = AI_IOACCESS_BUS_MASTER; 798 847 ptr->AdapterHostBus = AI_HOSTBUS_OTHER | AI_BUSWIDTH_32BIT; 799 848 ptr->AdapterFlags = AF_16M | AF_HW_SCATGAT; 800 801 /* AHCI limits S/G elements to 22 bits, thus we'll report only half of 802 * our S/G list buffers to reduce complexity. The command preparation code 803 * will always try to map as many S/G elements as possible so the physical 804 * S/G list capacity is not really wasted except in rare conditions where 805 * we need to split commands with long S/G lists without any suitable split 806 * points except those at the reported MaxHWSGList. 807 */ 808 ptr->MaxHWSGList = AHCI_MAX_SG / 2; 809 810 if (!ad_info->port_scan_done) { 811 /* First call; need to scan AHCI hardware for devices. Since this might 812 * be a lengthy operation, especially when init_reset is set, we'll mark 813 * the adapter as busy (new IORBs will only be queued but not executed) 814 * and release the spinlock while scanning the ports so interrupts will 815 * be processed. 816 */ 817 if (ad_info->busy) { 818 dprintf("error: port scan requested while adapter was busy\n"); 819 iorb_seterr(iorb, IOERR_CMD_SW_RESOURCE); 820 goto iocm_device_table_done; 849 ptr->MaxHWSGList = AHCI_MAX_SG / 2; /* AHCI S/G elements are 22 bits */ 850 851 if (dta < ad_info_cnt) { 852 /* this is a physical AHCI adapter */ 853 AD_INFO *ad_info = ad_infos + dta; 854 855 ptr->AdapterDevBus = AI_DEVBUS_ST506 | AI_DEVBUS_32BIT; 856 sprintf(ptr->AdapterName, "AHCI_%d", dta); 857 858 if (!ad_info->port_scan_done) { 859 /* first call; need to scan AHCI hardware for devices */ 860 if (ad_info->busy) { 861 dprintf("error: port scan requested while adapter was busy\n"); 862 iorb_seterr(iorb, IOERR_CMD_SW_RESOURCE); 863 goto iocm_device_table_done; 864 } 865 ad_info->busy = 1; 866 spin_unlock(drv_lock); 867 rc = ahci_scan_ports(ad_info); 868 spin_lock(drv_lock); 869 ad_info->busy = 0; 870 871 if (rc != 0) { 872 dprintf("error: port scan failed on adapter #%d\n", dta); 873 iorb_seterr(iorb, IOERR_CMD_SW_RESOURCE); 874 goto iocm_device_table_done; 875 } 876 ad_info->port_scan_done = 1; 821 877 } 822 ad_info->busy = 1; 823 spin_unlock(drv_lock); 824 rc = ahci_scan_ports(ad_info); 825 spin_lock(drv_lock); 826 ad_info->busy = 0; 827 828 if (rc != 0) { 829 dprintf("error: port scan failed on adapter #%d\n", a); 830 iorb_seterr(iorb, IOERR_CMD_SW_RESOURCE); 831 goto iocm_device_table_done; 832 } 833 ad_info->port_scan_done = 1; 834 } 835 836 /* insert devices (units) into the device table */ 837 for (p = 0; p <= ad_info->port_max; p++) { 838 for (d = 0; d <= ad_info->ports[p].dev_max; d++) { 839 if (ad_info->ports[p].devs[d].present) { 840 UNITINFO _far *ui = ptr->UnitInfo + units; 841 842 /* sanity check for sufficient space in device table */ 843 if ((u32) (ui + 1) - (u32) dt > iorb_conf->DeviceTableLen) { 844 dprintf("error: device table provided by DASD too small\n"); 845 iorb_seterr(iorb, IOERR_CMD_SW_RESOURCE); 846 goto iocm_device_table_done; 878 879 /* insert physical (i.e. AHCI) devices into the device table */ 880 for (p = 0; p <= ad_info->port_max; p++) { 881 for (d = 0; d <= ad_info->ports[p].dev_max; d++) { 882 if (ad_info->ports[p].devs[d].present) { 883 if (ad_info->ports[p].devs[d].atapi && emulate_scsi[dta][p]) { 884 /* only report this unit as SCSI unit */ 885 scsi_units++; 886 continue; 887 } 888 if (add_unit_info(iorb_conf, dta, dta, p, d, 0)) { 889 goto iocm_device_table_done; 890 } 847 891 } 848 849 if (ad_info->ports[p].devs[d].unit_info == NULL) {850 /* provide initial information about this device (unit) */851 memset(ui, 0x00, sizeof(*ui));852 ui->AdapterIndex = a;853 ui->UnitIndex = units;854 ui->UnitHandle = iorb_unit(a, p, d);855 ui->UnitType = ad_info->ports[p].devs[d].dev_type;856 ui->QueuingCount = ad_info->ports[p].devs[d].ncq_max;;857 if (ad_info->ports[p].devs[d].removable) {858 ui->UnitFlags |= UF_REMOVABLE;859 }860 } else {861 /* copy updated device (unit) information (IOCM_CHANGE_UNITINFO) */862 memcpy(ui, ad_info->ports[p].devs[d].unit_info, sizeof(*ui));863 }864 units++;865 892 } 866 893 } 867 } 868 869 /* set total device (unit) count for this adapter */ 870 ptr->AdapterUnits = units; 894 895 } else { 896 /* this is the virtual SCSI adapter */ 897 if (scsi_units == 0) { 898 /* not a single unit to be emulated via SCSI */ 899 dt->TotalAdapters--; 900 break; 901 } 902 903 /* set adapter name and bus type to mimic a SCSI controller */ 904 ptr->AdapterDevBus = AI_DEVBUS_SCSI_2 | AI_DEVBUS_16BIT; 905 sprintf(ptr->AdapterName, "AHCI_SCSI_0"); 906 907 /* add all ATAPI units to be emulated by this virtual adaper */ 908 for (a = 0; a < ad_info_cnt; a++) { 909 AD_INFO *ad_info = ad_infos + a; 910 911 for (p = 0; p <= ad_info->port_max; p++) { 912 for (d = 0; d <= ad_info->ports[p].dev_max; d++) { 913 if (ad_info->ports[p].devs[d].present && 914 ad_info->ports[p].devs[d].atapi && 915 emulate_scsi[a][p]) { 916 if (add_unit_info(iorb_conf, dta, a, p, d, scsi_id++)) { 917 goto iocm_device_table_done; 918 } 919 } 920 } 921 } 922 } 923 } 871 924 872 925 /* calculate offset for next adapter */ 873 pos = (char _far *) (ptr->UnitInfo + units);926 pos = (char _far *) (ptr->UnitInfo + ptr->AdapterUnits); 874 927 } 875 928 … … 1088 1141 * Due to this logic, this function is only good for simple task-time 1089 1142 * completions. Functions working on lists of IORBs (such as interrupt 1090 * handlers or context hooks) should implement their own logic. See 1091 * abort_ctxhook() for an example. 1143 * handlers or context hooks) should call iorb_complete() directly and 1144 * implement their own logic for removing the IORB from the port queue. 1145 * See abort_ctxhook() for an example. 1092 1146 */ 1093 1147 void iorb_done(IORBH _far *iorb) … … 1106 1160 spin_unlock(drv_lock); 1107 1161 1108 complete_iorb(iorb); 1162 iorb_complete(iorb); 1163 } 1164 1165 /****************************************************************************** 1166 * Complete an IORB. It should be called without the adapter-level spinlock 1167 * to allow the IORB completion routine to perform whatever processing it 1168 * requires. This implies that the IORB should no longer be in any global 1169 * queue because the IORB completion routine may well reuse the IORB and send 1170 * the next request to us before even returning from this function. 1171 */ 1172 void iorb_complete(IORBH _far *iorb) 1173 { 1174 iorb->Status |= IORB_DONE; 1175 1176 dprintf("IORB %Fp complete (status = 0x%04x, error = 0x%04x)\n", 1177 iorb, iorb->Status, iorb->ErrorCode); 1178 1179 if (iorb->RequestControl & IORB_ASYNC_POST) { 1180 iorb->NotifyAddress(iorb); 1181 } 1109 1182 } 1110 1183 … … 1126 1199 memset(aws, 0x00, sizeof(*aws)); 1127 1200 aws->no_ncq = no_ncq; 1201 } 1202 1203 /****************************************************************************** 1204 * Free resources in ADD workspace (timer, buffer, ...). This function should 1205 * be called with the spinlock held to prevent race conditions. 1206 */ 1207 void aws_free(ADD_WORKSPACE _far *aws) 1208 { 1209 if (aws->timer != 0) { 1210 ADD_CancelTimer(aws->timer); 1211 aws->timer = 0; 1212 } 1213 1214 if (aws->buf != NULL) { 1215 free(aws->buf); 1216 aws->buf = NULL; 1217 } 1128 1218 } 1129 1219 … … 1201 1291 { 1202 1292 } 1293 1294 /****************************************************************************** 1295 * Add unit info to ADAPTERINFO array (IOCC_GET_DEVICE_TABLE requests). The 1296 * adapter info array in the device table, dt->pAdapter[], is expected to be 1297 * initialized for the specified index (dt_ai). 1298 * 1299 * Please note that the device table adapter index, dta, is not always equal 1300 * to the physical adapter index, a: if SCSI emulation has been activated, the 1301 * last reported adapter is a virtual SCSI adapter and the physical adapter 1302 * indexes for those units are, of course, different from the device table 1303 * index of the virtual SCSI adapter. 1304 */ 1305 static int add_unit_info(IORB_CONFIGURATION _far *iorb_conf, int dta, 1306 int a, int p, int d, int scsi_id) 1307 { 1308 DEVICETABLE _far *dt = iorb_conf->pDeviceTable; 1309 ADAPTERINFO _far *ptr = (ADAPTERINFO _far *) (((u32) dt & 0xffff0000U) + 1310 (u16) dt->pAdapter[dta]); 1311 UNITINFO _far *ui = ptr->UnitInfo + ptr->AdapterUnits; 1312 AD_INFO *ai = ad_infos + a; 1313 1314 if ((u32) (ui + 1) - (u32) dt > iorb_conf->DeviceTableLen) { 1315 dprintf("error: device table provided by DASD too small\n"); 1316 iorb_seterr(&iorb_conf->iorbh, IOERR_CMD_SW_RESOURCE); 1317 return(-1); 1318 } 1319 1320 if (ai->ports[p].devs[d].unit_info == NULL) { 1321 /* provide original information about this device (unit) */ 1322 memset(ui, 0x00, sizeof(*ui)); 1323 ui->AdapterIndex = dta; /* device table adapter index */ 1324 ui->UnitHandle = iorb_unit(a, p, d); /* physical adapter index */ 1325 ui->UnitIndex = ptr->AdapterUnits; 1326 ui->UnitType = ai->ports[p].devs[d].dev_type; 1327 ui->QueuingCount = ai->ports[p].devs[d].ncq_max;; 1328 if (ai->ports[p].devs[d].removable) { 1329 ui->UnitFlags |= UF_REMOVABLE; 1330 } 1331 if (scsi_id > 0) { 1332 /* set fake SCSI ID for this unit */ 1333 ui->UnitSCSITargetID = scsi_id; 1334 } 1335 } else { 1336 /* copy updated device (unit) information (IOCM_CHANGE_UNITINFO) */ 1337 memcpy(ui, ai->ports[p].devs[d].unit_info, sizeof(*ui)); 1338 } 1339 1340 ptr->AdapterUnits++; 1341 return(0); 1342 } 1343
Note:
See TracChangeset
for help on using the changeset viewer.