Ignore:
Timestamp:
Jul 24, 2023, 5:51:46 PM (2 years ago)
Author:
David Azarewicz
Message:

Added workaround to help with VirtualBox issues.
Improved diagnostic messages.
Changed how timeouts are reset and how ctx hooks are triggered.
Added quirk for devices with issues executing some standard commands.
Changed to make /N the default.

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/os2ahci/ctxhook.c

    r209 r211  
    44 * Copyright (c) 2011 thi.guten Software Development
    55 * Copyright (c) 2011 Mensys B.V.
    6  * Copyright (c) 2013-2021 David Azarewicz <david@88watts.net>
     6 * Copyright (c) 2013-2023 David Azarewicz <david@88watts.net>
    77 *
    88 * Authors: Christian Mueller, Markus Thielen
     
    3131
    3232/* port restart context hook and input data */
    33 ULONG           restart_ctxhook_h;
     33ULONG           RestartCtxHook_h;
    3434volatile u32    ports_to_restart[MAX_AD];
    3535
    3636/* port reset context hook and input data */
    37 ULONG           reset_ctxhook_h;
    38 ULONG           th_reset_watchdog;
     37ULONG           ResetCtxHook_h;
     38ULONG           th_watchdog;
    3939volatile u32    ports_to_reset[MAX_AD];
    4040IORB_QUEUE      abort_queue;
     
    4242/* trigger engine context hook and input data */
    4343ULONG           engine_ctxhook_h;
     44
     45#define QUEUEDEPTH 8
     46static struct _ctxq_
     47{
     48  ULONG ulHandle;
     49  ULONG ulArg;
     50} CtxQueue[QUEUEDEPTH] = {0};
     51static ULONG ulCtxStatusFlag = 0;
     52
     53void SafeArmCtxHook(ULONG ulHandle, ULONG armData)
     54{
     55  USHORT i;
     56
     57  i = LockInc(&ulCtxStatusFlag);
     58
     59  if (i)
     60  {
     61    i--;
     62    if (i < QUEUEDEPTH)
     63    {
     64      CtxQueue[i].ulHandle = ulHandle;
     65      CtxQueue[i].ulArg = armData;
     66    }
     67  }
     68  else
     69  {
     70    KernArmHook(ulHandle, armData, 0);
     71  }
     72}
     73
     74void ClearThreadStatus(ULONG ulHandle)
     75{
     76  USHORT i;
     77
     78  i = LockDec(&ulCtxStatusFlag);
     79
     80  if (i)
     81  {
     82    i--;
     83    if (i < QUEUEDEPTH)
     84    {
     85      KernArmHook(CtxQueue[i].ulHandle, CtxQueue[i].ulArg, 0);
     86    }
     87    else
     88    {
     89      KernArmHook(ulHandle, 0, 0);
     90    }
     91  }
     92}
    4493
    4594/******************************************************************************
     
    78127 * in the interrupt and error handlers.
    79128 */
    80 void _Syscall restart_ctxhook(ULONG parm)
     129void _Syscall RestartCtxHook(ULONG parm)
    81130{
    82131  IORB_QUEUE done_queue;
     
    85134  IORBH FAR16DATA *vIorb;
    86135  IORBH FAR16DATA *vNext;
     136  IORBH *pIorb;
     137  ADD_WORKSPACE *aws;
    87138  u8 *port_mmio;
    88139  int rearm_ctx_hook;
     
    97148  rearm_ctx_hook = 0;
    98149
    99   DPRINTF(DBG_FUNCBEG, DBG_PREFIX": restart_ctxhook() started\n");
     150  AhciStats.ulSoftErrorCount++;
     151  DPRINTF(0, DBG_PREFIX": BEG\n");
    100152  memset(&done_queue, 0x00, sizeof(done_queue));
    101153
    102154  spin_lock(drv_lock);
     155
     156  if (th_watchdog != 0)
     157  {
     158    /* watchdog timer still active -- just reset it */
     159    Timer_CancelTimer(th_watchdog);
     160    th_watchdog = 0;
     161  }
    103162
    104163  for (a = 0; a < ad_info_cnt; a++)
     
    124183        need_reset = 0;
    125184
    126         DPRINTF(DBG_DETAILED, DBG_PREFIX": port %d, TF_DATA: 0x%x\n", p, readl(port_mmio + PORT_TFDATA));
     185        DPRINTF(DBG_DETAILED, DBG_PREFIX": port=%d TF_DATA=0x%x\n", p, readl(port_mmio + PORT_TFDATA));
    127186
    128187        /* get "current command slot"; only valid if there are no NCQ cmds */
    129188        ccs = (int) ((readl(port_mmio + PORT_CMD) >> 8) & 0x1f);
    130         DPRINTF(DBG_DETAILED, DBG_PREFIX": PORT_CMD      = 0x%x\n", ccs);
     189        DPRINTF(DBG_DETAILED, DBG_PREFIX": PORT_CMD=0x%x\n", ccs);
    131190
    132191        for (vIorb = ai->ports[p].iorb_queue.vRoot; vIorb != FAR16NULL; vIorb = vNext)
    133192        {
    134           IORBH *pIorb = Far16ToFlat(vIorb);
    135           ADD_WORKSPACE *aws = add_workspace(pIorb);
     193          pIorb = Far16ToFlat(vIorb);
     194          aws = add_workspace(pIorb);
    136195          vNext = pIorb->f16NxtIORB;
    137196
    138197          if (aws->queued_hw)
    139198          {
     199            if (aws->timer != 0)
     200            {
     201              Timer_CancelTimer(aws->timer);
     202              aws->timer = 0;
     203            }
     204
    140205            if (ai->ports[p].ncq_cmds & (1UL << aws->cmd_slot))
    141206            {
     
    144209              aws->no_ncq = 1;
    145210              need_reset = 1;
     211              DPRINTF(0, DBG_PREFIX": failing IORB: %x NCQ slot=%x\n", vIorb, aws->cmd_slot);
     212              #ifdef DEBUG
     213              DumpIorb(pIorb, vIorb);
     214              #endif
    146215            }
    147216            else
     
    152221              {
    153222                /* this is the non-NCQ command that failed */
    154                 DPRINTF(0, DBG_PREFIX": failing IORB: %x\n", vIorb);
     223                DPRINTF(0, DBG_PREFIX": failing IORB: %x slot=%x\n", vIorb, aws->cmd_slot);
     224                #ifdef DEBUG
     225                DumpIorb(pIorb, vIorb);
     226                #endif
    155227                vProblemIorb = vIorb;
    156228              }
     
    179251        if (ai->ports[p].ncq_cmds != 0 || ai->ports[p].reg_cmds != 0)
    180252        {
    181           DPRINTF(0, DBG_PREFIX": warning: commands issued not 0 (%08lx/%08lx); resetting...\n",
     253          DPRINTF(0, DBG_PREFIX": warning: commands issued not 0 (%08x/%08x); resetting...\n",
    182254                  ai->ports[p].ncq_cmds, ai->ports[p].reg_cmds);
    183255          need_reset = 1;
     
    260332  spin_unlock(drv_lock);
    261333
     334  DPRINTF(0, DBG_PREFIX": Resuming\n");
    262335  /* call notification routine on all IORBs which have completed */
    263336  for (vIorb = done_queue.vRoot; vIorb != FAR16NULL; vIorb = vNext)
    264337  {
    265     IORBH *pIorb = Far16ToFlat(vIorb);
     338    pIorb = Far16ToFlat(vIorb);
    266339    vNext = pIorb->f16NxtIORB;
    267340
     
    278351  spin_unlock(drv_lock);
    279352
    280   DPRINTF(DBG_FUNCEND, DBG_PREFIX": restart_ctxhook() completed\n");
     353  DPRINTF(0, DBG_PREFIX": END Rearm=%x\n", rearm_ctx_hook);
    281354
    282355  /* Check whether we have to rearm ourselves because some adapters were busy
     
    285358  if (rearm_ctx_hook)
    286359  {
    287     msleep(250);
    288     KernArmHook(restart_ctxhook_h, 0, 0);
    289   }
     360    /* we cannot rearm ourself because we will execute immediately leaving
     361     * no time to process and clear the reason we need to rearm. Therefore
     362     * we set the timer again.
     363     */
     364    Timer_StartTimerMS(&th_watchdog, 250, WatchdogTimer, RestartCtxHook_h);
     365  }
     366
     367  ClearThreadStatus(RestartCtxHook_h);
    290368  KernThunkStackTo16();
    291369}
     
    317395 * the upstream code might reuse the IORBs before we're done with them.
    318396 */
    319 void _Syscall reset_ctxhook(ULONG parm)
     397void _Syscall ResetCtxHook(ULONG ulArg)
    320398{
    321399  IORB_QUEUE done_queue;
     
    323401  IORBH FAR16DATA *vIorb;
    324402  IORBH FAR16DATA *vNext;
     403  IORBH *pIorb;
     404  ADD_WORKSPACE *aws;
    325405  int rearm_ctx_hook;
    326406  int a;
     
    332412  rearm_ctx_hook = 0;
    333413
    334   DPRINTF(DBG_FUNCBEG, DBG_PREFIX": reset_ctxhook() started\n");
     414  AhciStats.ulHardErrorCount++;
     415  DPRINTF(0, DBG_PREFIX": BEG Arg=%x\n", ulArg);
    335416  memset(&done_queue, 0x00, sizeof(done_queue));
    336417
     418  if (th_watchdog != 0)
     419  {
     420    /* watchdog timer still active -- just reset it */
     421    Timer_CancelTimer(th_watchdog);
     422    th_watchdog = 0;
     423  }
     424
    337425  spin_lock(drv_lock);
    338426
    339   if (th_reset_watchdog != 0)
    340   {
    341     /* watchdog timer still active -- just reset it */
    342     Timer_CancelTimer(th_reset_watchdog);
    343     th_reset_watchdog = 0;
     427  if (ulArg)
     428  {
     429    /* Move the timed-out IORB to the abort queue. Since it's possible that the
     430     * IORB has completed after the timeout has expired but before we got to
     431     * this line of code, we'll check the return code of iorb_queue_del(): If it
     432     * returns an error, the IORB must have completed a few microseconds ago and
     433     * there is no timeout.
     434     */
     435    vIorb = (IORBH FAR16DATA *)CastULONGToFar16(ulArg);
     436    pIorb = Far16ToFlat(vIorb);
     437    a = iorb_unit_adapter(pIorb);
     438    p = iorb_unit_port(pIorb);
     439    if (iorb_queue_del(&ad_infos[a].ports[p].iorb_queue, vIorb) == 0)
     440    {
     441      pIorb = Far16ToFlat(vIorb);
     442      iorb_queue_add(&abort_queue, vIorb, pIorb);
     443      pIorb->ErrorCode = IOERR_ADAPTER_TIMEOUT;
     444    }
    344445  }
    345446
     
    347448  for (vIorb = abort_queue.vRoot; vIorb != FAR16NULL; vIorb = vNext)
    348449  {
    349     IORBH *pIorb = Far16ToFlat(vIorb);
     450    pIorb = Far16ToFlat(vIorb);
    350451    vNext = pIorb->f16NxtIORB;
    351452    a = iorb_unit_adapter(pIorb);
    352453    p = iorb_unit_port(pIorb);
    353454    ai = ad_infos + a;
     455    aws = add_workspace(pIorb);
    354456
    355457    if (ai->busy)
     
    365467
    366468    /* reset port if the IORB has already been queued to hardware */
    367     if (add_workspace(pIorb)->queued_hw)
    368     {
     469    if (aws->queued_hw)
     470    {
     471      if (aws->timer != 0)
     472      {
     473        Timer_CancelTimer(aws->timer);
     474        aws->timer = 0;
     475      }
     476
    369477      /* prepare port reset */
    370478      ports_to_reset[a] |= (1UL << p);
     
    411519        {
    412520          IORBH *pIorb = Far16ToFlat(vIorb);
    413           ADD_WORKSPACE *aws = add_workspace(pIorb);
    414521          vNext = pIorb->f16NxtIORB;
     522
     523          aws = add_workspace(pIorb);
    415524
    416525          if (aws->queued_hw)
     
    421530              /* we can retry this IORB */
    422531              iorb_requeue(pIorb);
    423 
    424532            }
    425533            else
     
    438546  spin_unlock(drv_lock);
    439547
     548  DPRINTF(0, DBG_PREFIX": Resuming\n");
     549
    440550  /* complete all aborted IORBs */
    441551  for (vIorb = done_queue.vRoot; vIorb != FAR16NULL; vIorb = vNext)
    442552  {
    443     IORBH *pIorb = Far16ToFlat(vIorb);
     553    pIorb = Far16ToFlat(vIorb);
    444554    vNext = pIorb->f16NxtIORB;
    445555
     
    457567  spin_unlock(drv_lock);
    458568
    459   DPRINTF(DBG_FUNCEND, DBG_PREFIX": reset_ctxhook() completed\n");
     569  DPRINTF(0, DBG_PREFIX": END Rearm=%x\n", rearm_ctx_hook);
    460570
    461571  /* Check whether we have to rearm ourselves because some adapters were busy
     
    468578     * we set the timer again.
    469579     */
    470     //msleep(250);
    471     //KernArmHook(reset_ctxhook_h, 0, 0);
    472     Timer_StartTimerMS(&th_reset_watchdog, 250, reset_watchdog, 0);
    473   }
    474 
     580    Timer_StartTimerMS(&th_watchdog, 250, WatchdogTimer, ResetCtxHook_h);
     581  }
     582
     583  ClearThreadStatus(ResetCtxHook_h);
    475584  KernThunkStackTo16();
    476585}
Note: See TracChangeset for help on using the changeset viewer.