Changeset 125 for trunk/src/os2ahci/ioctl.c
- Timestamp:
- Oct 8, 2011, 10:28:48 PM (14 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/os2ahci/ioctl.c
r113 r125 27 27 #include "os2ahci.h" 28 28 #include "atapi.h" 29 #include "ata.h" 29 30 #include "ioctl.h" 30 31 … … 42 43 * we'll need to define a union to cover all IORB types in question. 43 44 */ 45 #define CMDLEN sizeof(((OS2AHCI_PASSTHROUGH *) 0)->cmd) 44 46 typedef struct { 45 47 IORB_ADAPTER_PASSTHRU iorb; /* IORB */ 46 48 SCSI_STATUS_BLOCK ssb; /* SCSI status block */ 49 UCHAR cmd[CMDLEN]; /* copy of passthrough cmd 50 * (need to fill ATA return 51 * registers at interrupt time) 52 */ 47 53 UCHAR sense[ATAPI_SENSE_LEN]; /* sense buffer */ 48 54 SCATGATENTRY sg_lst[AHCI_MAX_SG / 2]; /* scatter/gather list */ … … 53 59 /* -------------------------- function prototypes -------------------------- */ 54 60 55 static LIN lin(void _far *p); 61 static USHORT do_smart (BYTE unit, BYTE sub_func, BYTE parm, void _far *buf); 62 static int map_unit (BYTE unit, USHORT _far *a, USHORT _far *p, 63 USHORT _far *d); 64 static LIN lin (void _far *p); 56 65 57 66 IORBH _far * _far _cdecl ioctl_wakeup(IORBH _far *iorb); … … 171 180 return(STDON | STERR | ERROR_I24_BAD_UNIT); 172 181 } 173 if ((req->buflen + 4095) / 4096 + 1 > AHCI_MAX_SG / 2) { 182 if ((req->buflen + 4095) / 4096 + 1 > AHCI_MAX_SG / 2 || 183 req->cmdlen < 6 || req->cmdlen > sizeof(req->cmd)) { 174 184 return(STDON | STERR | ERROR_I24_INVALID_PARAMETER); 175 185 } … … 206 216 ic->iorb.ppSGLIST = virt_to_phys(ic->sg_lst); 207 217 218 memcpy(ic->cmd, req->cmd.cdb, sizeof(ic->cmd)); 208 219 ic->iorb.ControllerCmdLen = req->cmdlen; 209 ic->iorb.pControllerCmd = req->cmd.cdb;220 ic->iorb.pControllerCmd = ic->cmd; 210 221 ic->iorb.Flags = (req->flags & PT_WRITE) ? 0 : PT_DIRECTION_IN; 211 222 … … 236 247 spin_lock(drv_lock); 237 248 while (!(ic->iorb.iorbh.Status & IORB_DONE)) { 249 238 250 # ifndef OS2AHCI_SMP 239 251 drv_lock = 0; 240 252 # endif 253 241 254 DevHelp_ProcBlock((ULONG) (void _far *) &ic->iorb.iorbh, 30000, 1); 242 255 spin_lock(drv_lock); … … 306 319 min(ic->ssb.ReqSenseLen, req->sense_len)); 307 320 } 321 322 } else if ((req->flags & PT_ATAPI) == 0) { 323 /* Copy ATA cmd back to IOCTL request (ATA commands are effectively 324 * registers which are sometimes used to indicate return conditions, 325 * e.g. when requesting the smart status) 326 */ 327 memcpy(&req->cmd.ata, ic->cmd, sizeof(req->cmd.ata)); 308 328 } 309 329 … … 316 336 317 337 /****************************************************************************** 338 * Generic disk IOCTL handler; this IOCTL category has originally been defined 339 * in IBM1S506; the code has been more or less copied from DANIS506. 340 * 341 * NOTE: Only a subset of the IOCTL calls are implemented in OS2AHCI at this 342 * point, basically those calls required to get HDMON working. 343 */ 344 USHORT ioctl_gen_dsk(RP_GENIOCTL _far *ioctl) 345 { 346 DSKSP_CommandParameters _far *cp = (DSKSP_CommandParameters _far *) ioctl->ParmPacket; 347 UnitInformationData _far *ui; 348 OS2AHCI_PASSTHROUGH pt; 349 RP_GENIOCTL tmp_ioctl; 350 USHORT size = 0; 351 USHORT ret; 352 USHORT a; 353 USHORT p; 354 USHORT d; 355 UCHAR unit; 356 357 /* verify addressability of parm buffer (DSKSP_CommandParameters) */ 358 if (DevHelp_VerifyAccess((SEL) ((ULONG) cp >> 16), 359 sizeof(DSKSP_CommandParameters), 360 (USHORT) (ULONG) cp, 361 VERIFY_READONLY) != 0) { 362 return(STDON | STERR | 0x05); 363 } 364 unit = cp->byPhysicalUnit; 365 366 /* verify addressability of data buffer (depends on function code) */ 367 switch (ioctl->Function) { 368 369 case DSKSP_GEN_GET_COUNTERS: 370 size = sizeof(DeviceCountersData); 371 break; 372 373 case DSKSP_GET_UNIT_INFORMATION: 374 size = sizeof(UnitInformationData); 375 break; 376 377 case DSKSP_GET_INQUIRY_DATA: 378 size = ATA_ID_WORDS * sizeof(u16); 379 break; 380 } 381 382 if (size > 0) { 383 if (DevHelp_VerifyAccess((SEL) ((ULONG) ioctl->DataPacket >> 16), 384 size, (USHORT) (ULONG) ioctl->DataPacket, 385 VERIFY_READWRITE) != 0) { 386 return(STDON | STERR | 0x05); 387 } 388 } 389 390 if (map_unit(unit, &a, &p, &d)) { 391 return(STDON | STERR | ERROR_I24_BAD_UNIT); 392 } 393 394 /* execute generic disk request */ 395 switch (ioctl->Function) { 396 397 case DSKSP_GEN_GET_COUNTERS: 398 /* Not supported, yet; we would need dynamically allocated device 399 * structures to cope with the memory requirements of the corresponding 400 * statistics buffer. For the time being, we'll return an empty buffer. 401 */ 402 memset(ioctl->DataPacket, 0x00, sizeof(DeviceCountersData)); 403 ret = STDON; 404 break; 405 406 case DSKSP_GET_UNIT_INFORMATION: 407 /* get unit information; things like port addresses won't fit so we don't 408 * even bother returning those. 409 */ 410 ui = (UnitInformationData _far *) ioctl->DataPacket; 411 memset(ui, 0x00, sizeof(*ui)); 412 413 ui->wRevisionNumber = 1; 414 ui->wIRQ = ad_infos[a].irq; 415 ui->wFlags = UIF_VALID; 416 ui->wFlags |= UIF_RUNNING_BMDMA; 417 ui->wFlags |= (unit & 0x0001) ? UIF_SLAVE : 0; 418 ui->wFlags |= (ad_infos[a].ports[p].devs[d].atapi) ? UIF_ATAPI : 0; 419 ui->wFlags |= UIF_SATA; 420 421 ret = STDON; 422 break; 423 424 case DSKSP_GET_INQUIRY_DATA: 425 /* return ATA ID buffer */ 426 memset(&tmp_ioctl, 0x00, sizeof(tmp_ioctl)); 427 tmp_ioctl.Category = OS2AHCI_IOCTL_CATEGORY; 428 tmp_ioctl.Function = OS2AHCI_IOCTL_PASSTHROUGH; 429 tmp_ioctl.ParmPacket = (void _far *) &pt; 430 431 memset(&pt, 0x00, sizeof(pt)); 432 pt.adapter = a; 433 pt.port = p; 434 pt.device = d; 435 pt.cmdlen = sizeof(pt.cmd.ata); 436 pt.cmd.ata.cmd = (ad_infos[a].ports[p].devs[d].atapi) ? 437 ATA_CMD_ID_ATAPI : ATA_CMD_ID_ATA; 438 pt.buflen = size; 439 pt.buf = lin(ioctl->DataPacket); 440 441 ret = gen_ioctl(&tmp_ioctl); 442 break; 443 444 default: 445 ret = STDON | STATUS_ERR_UNKCMD; 446 break; 447 } 448 449 return(ret); 450 } 451 452 /****************************************************************************** 453 * SMART IOCTL handler; this IOCTL category has originally been defined in 454 * IBM1S506; the code has been more or less copied from DANIS506. 455 */ 456 USHORT ioctl_smart(RP_GENIOCTL _far *ioctl) 457 { 458 DSKSP_CommandParameters _far *cp = (DSKSP_CommandParameters _far *) ioctl->ParmPacket; 459 USHORT size = 0; 460 USHORT ret; 461 UCHAR unit; 462 UCHAR parm; 463 464 /* verify addressability of parm buffer (DSKSP_CommandParameters) */ 465 if (DevHelp_VerifyAccess((SEL) ((ULONG) cp >> 16), 466 sizeof(DSKSP_CommandParameters), 467 (USHORT) (ULONG) cp, 468 VERIFY_READONLY) != 0) { 469 return(STDON | STERR | 0x05); 470 } 471 unit = cp->byPhysicalUnit; 472 473 /* verify addressability of data buffer (depends on SMART function) */ 474 switch (ioctl->Function) { 475 476 case DSKSP_SMART_GETSTATUS: 477 size = sizeof(ULONG); 478 break; 479 480 case DSKSP_SMART_GET_ATTRIBUTES: 481 case DSKSP_SMART_GET_THRESHOLDS: 482 case DSKSP_SMART_GET_LOG: 483 size = 512; 484 break; 485 } 486 487 if (size > 0) { 488 if (DevHelp_VerifyAccess((SEL) ((ULONG) ioctl->DataPacket >> 16), 489 size, (USHORT) (ULONG) ioctl->DataPacket, 490 VERIFY_READWRITE) != 0) { 491 return(STDON | STERR | 0x05); 492 } 493 parm = ioctl->DataPacket[0]; 494 } 495 496 /* execute SMART request */ 497 switch (ioctl->Function) { 498 499 case DSKSP_SMART_ONOFF: 500 ret = do_smart(unit, 501 (BYTE) ((parm) ? ATA_SMART_ENABLE 502 : ATA_SMART_DISABLE), 503 0, NULL); 504 break; 505 506 case DSKSP_SMART_AUTOSAVE_ONOFF: 507 ret = do_smart(unit, ATA_SMART_AUTOSAVE, 508 (BYTE) ((parm) ? (BYTE) 0xf1 : 0), 509 NULL); 510 break; 511 512 case DSKSP_SMART_AUTO_OFFLINE: 513 ret = do_smart(unit, ATA_SMART_AUTO_OFFLINE, parm, NULL); 514 break; 515 516 case DSKSP_SMART_EXEC_OFFLINE: 517 ret = do_smart(unit, ATA_SMART_IMMEDIATE_OFFLINE, parm, NULL); 518 break; 519 520 case DSKSP_SMART_SAVE: 521 ret = do_smart(unit, ATA_SMART_SAVE, 0, NULL); 522 break; 523 524 case DSKSP_SMART_GETSTATUS: 525 ret = do_smart(unit, ATA_SMART_STATUS, 0, ioctl->DataPacket); 526 break; 527 528 case DSKSP_SMART_GET_ATTRIBUTES: 529 ret = do_smart(unit, ATA_SMART_READ_VALUES, 0, ioctl->DataPacket); 530 break; 531 532 case DSKSP_SMART_GET_THRESHOLDS: 533 ret = do_smart(unit, ATA_SMART_READ_THRESHOLDS, 0, ioctl->DataPacket); 534 break; 535 536 case DSKSP_SMART_GET_LOG: 537 ret = do_smart(unit, ATA_SMART_READ_LOG, parm, ioctl->DataPacket); 538 break; 539 540 default: 541 ret = STDON | STATUS_ERR_UNKCMD; 542 } 543 544 return(ret); 545 } 546 547 /****************************************************************************** 548 * Perform SMART request. The code has been more or less copied from DANIS506. 549 */ 550 static USHORT do_smart(BYTE unit, BYTE sub_func, BYTE parm, void _far *buf) 551 { 552 OS2AHCI_PASSTHROUGH pt; 553 RP_GENIOCTL ioctl; 554 USHORT ret; 555 USHORT a; 556 USHORT p; 557 USHORT d; 558 559 if (map_unit(unit, &a, &p, &d)) { 560 return(STDON | STERR | ERROR_I24_BAD_UNIT); 561 } 562 563 /* Perform SMART request using the existing OS2AHCI_IOTCL_PASSTHROUGH IOCTL 564 * interface which already takes care of allocating an IORB, s/g lists, etc. 565 */ 566 memset(&ioctl, 0x00, sizeof(ioctl)); 567 ioctl.Category = OS2AHCI_IOCTL_CATEGORY; 568 ioctl.Function = OS2AHCI_IOCTL_PASSTHROUGH; 569 ioctl.ParmPacket = (void _far *) &pt; 570 571 memset(&pt, 0x00, sizeof(pt)); 572 pt.adapter = a; 573 pt.port = p; 574 pt.device = d; 575 pt.cmdlen = sizeof(pt.cmd.ata); 576 pt.cmd.ata.features = sub_func; 577 pt.cmd.ata.count = parm; 578 pt.cmd.ata.lba_l = (0xc24fL << 8) | parm; 579 pt.cmd.ata.cmd = ATA_CMD_SMART; 580 581 if (buf != NULL && sub_func != ATA_SMART_STATUS) { 582 pt.buflen = 512; 583 pt.buf = lin(buf); 584 } 585 586 if (((ret = gen_ioctl(&ioctl)) & STERR) == 0 && 587 sub_func == ATA_SMART_STATUS) { 588 589 /* ATA_SMART_STATUS doesn't transfer anything but instead relies on the 590 * returned D2H FIS, mapped to the ATA CMD, to have a certain value 591 * (0xf42c); the IOCTL result is expected to be returned as a ULONG in 592 * the data buffer. 593 */ 594 if (((pt.cmd.ata.lba_l >> 8) & 0xffff) == 0xf42c) { 595 *((ULONG _far *) buf) = 1; 596 } else { 597 *((ULONG _far *) buf) = 0; 598 } 599 } 600 601 return(ret); 602 } 603 604 /****************************************************************************** 605 * Map DSKSP unit number to corresponding adapter/port/device number. Units 606 * are identified by an 8-bit adapter/device number with the lowest bit 607 * selecting between master (0) and slave (1). This number is mapped to our 608 * ATA/ATAPI units sequentially. 609 */ 610 static int map_unit(BYTE unit, USHORT _far *a, USHORT _far *p, USHORT _far *d) 611 { 612 USHORT _a; 613 USHORT _p; 614 USHORT _d; 615 616 /* map unit to adapter/port/device */ 617 for (_a = 0; _a < ad_info_cnt; _a++) { 618 AD_INFO *ai = ad_infos + _a; 619 620 for (_p = 0; _p <= ai->port_max; _p++) { 621 P_INFO *pi = ai->ports + _p; 622 623 for (_d = 0; _d <= pi->dev_max; _d++) { 624 if (pi->devs[_d].present) { 625 if (--unit == 0) { 626 /* found the device */ 627 *a = _a; 628 *p = _p; 629 *d = _d; 630 return(0); 631 } 632 } 633 } 634 } 635 } 636 637 /* unit not found */ 638 return(-1); 639 } 640 641 /****************************************************************************** 318 642 * Get linear address for specified virtual address. 319 643 */
Note:
See TracChangeset
for help on using the changeset viewer.