libcdio-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: [Libcdio-devel] Read Sub-channel changes


From: Thomas Schmitt
Subject: Re: [Libcdio-devel] Read Sub-channel changes
Date: Sat, 11 Jun 2016 09:51:14 +0200

Hi,

i want to show what i am testing now on GNU/Linux.

The patch is not yet ready for production software, because:

- mmc_get_mcn() is called unconditionally by get_mcn_linux().
  The old function mmc_get_mcn() is still in the code but deactivated
  by #ifdef.
  I did not check the other operating system drivers whether and
  how they obtain MCN.

- The operating system dependent run_mmc_cmd_*() functions have been
  augmented by two code lines, but only the one in gnu_linux.c was
  compiled and tested yet.
  I triple checked that the variable names match, but the following
  source modules still need testing:
    lib/driver/FreeBSD/freebsd_cam.c
    lib/driver/MSWindows/aspi32.c
    lib/driver/MSWindows/win32_ioctl.c (two occurences)
    lib/driver/osx.c
    lib/driver/solaris.c

- The new facility is used currently only by  mmc_get_mcn_isrc_private().
  Many other execution stacks of MMC commands need to be examined where
  to put the evaluation and whether particular special handling is needed.
  (E.g. from the command for ejecting the tray, one may get sense data
   indicating that there is no medium any more.)

- There is still a (deactivated) test code snippet by which i provoke
  failure and sense data of READ SUB-CHANNEL.

- The functions are possibly not yet in the source modules which Rocky
  would prefer. (Give me instructions and i will move them.)

- I got no reply yet from address@hidden


Implementation notes:

- I had to declare
    char *mmc_cdb_to_text(uint8_t *cdb, int cdb_len);
  and not
    char *mmc_cdb_to_text(mmc_cdb_t *cdb, int cdb_len);
  because i was unable to get mcc_util.h compiled when the latter
  prototype is in there.
  mmc_cdb_t is defined in mmc.h only after mmc_util.h was included.

=========================================================================
Base of development is the cdtext-testing branch as of 31 may 2016.
=========================================================================

diff --git a/include/cdio/mmc.h b/include/cdio/mmc.h
index f47f1d5..8a85905 100644
--- a/include/cdio/mmc.h
+++ b/include/cdio/mmc.h
@@ -798,6 +798,23 @@ driver_return_code_t mmc_audio_get_volume (CdIo_t *p_cdio, 
 /*out*/
                    /*in/out*/ void *p_buf );
 
   /**
+      Obtain a copy of the most-recently-performed MMC command bytes.
+
+      @param p_cdio    CD structure by which the MMC command was performed.
+      @param cdb       will in case of success point to a copy of the recorded
+                       CDB bytes. Dispose non-NULL pointers by cdio_free() when
+                       no longer needed.
+      @return          0 if no CDB is available.
+                       >0 gives the number of valid bytes in **cdb.
+   */
+   int mmc_last_cmd_cdb(const CdIo_t *p_cdio, mmc_cdb_t **cdb);
+
+  /**
+      Note: The layout of cdio_mmc_request_sense_t is valid only if the
+            value of  cdio_mmc_request_sense_t.error_code  is 0x70 or 0x71.
+            These values and the values 0x72 or 0x73 can be handled by
+            function mmc_last_cmd_key_asc_ascq().
+
       Obtain the SCSI sense reply of the most-recently-performed MMC command.
       These bytes give an indication of possible problems which occured in
       the drive while the command was performed. With some commands they tell
@@ -811,13 +828,87 @@ driver_return_code_t mmc_audio_get_volume (CdIo_t 
*p_cdio,  /*out*/
       codes as of SPC-3 Annex D, MMC-5 Annex F: sense[2]&15 = Key ,
       sense[12] = ASC , sense[13] = ASCQ
 
-      @return number of valid bytes in sense, 0 in case of no sense
-              bytes available, <0 in case of internal error.
+      @param p_cdio  CD structure set by cdio_open().
+      @return  number of valid bytes in sense, 0 in case of no sense
+               bytes available, <0 in case of internal error.
   */
   int mmc_last_cmd_sense ( const CdIo_t *p_cdio,
                            cdio_mmc_request_sense_t **pp_sense);
 
   /**
+      Obtain the sense code triple (key, asc, ascq) of the sense reply of the
+      most-recently-performed MMC command.
+      This serves for sense data in Fixed Format (0x70 or 0x71) and in
+      Descriptor Format (0x72, 0x73).
+
+      @param p_cdio  CD structure set by cdio_open().
+      @param key, asc, ascq return the triple of error codes from the
+             sense data.
+      @return 1 = the returned triple is valid
+              0 = no sense data available or not in a recognizable format
+  */
+  int mmc_last_cmd_key_asc_ascq( const CdIo_t *p_cdio, unsigned char *key,
+                                 unsigned char *asc, unsigned char *ascq);
+
+  /* Report mode of mmc_evaluate_sense_key_asc_ascq()
+     The values form a scale where higher numerical values mean more dramatic
+     reporting than lower numerical values. (If a new reporting class is
+     added, then it should be given the mean value of its neighbors.)
+  */
+  typedef enum {
+      CDIO_MMC_EVAL_SENSE_SILENT =     0,
+      CDIO_MMC_EVAL_SENSE_DEBUG  = 10000,
+      CDIO_MMC_EVAL_SENSE_INFO   = 20000,
+      CDIO_MMC_EVAL_SENSE_WARN   = 30000,
+      CDIO_MMC_EVAL_SENSE_ERROR  = 40000
+  } cdio_mmc_eval_sense_report_t;
+
+  /**
+     Evaluate the generic severity of the most-recently-performed MMC command
+     and optionally report problems via libcdio message functions.
+
+     This function bundles retrieval of sense data, evaluation of severity,
+     and formatting as human readable text. It should be suitable for handling
+     of sense replies of most SCSI/MMC commands.
+
+     Nevertheless, the particular severity of a sense code in relation to the
+     intention of a particular SCSI command and its parameters can deviate from
+     this evaluation.
+     E.g. it is no error if command START/STOP UNIT with Stop and Eject bit
+     returns sense code
+        2 3A 02 MEDIUM NOT PRESENT  TRAY OPEN
+     but rather an explicit confirmation of success.
+     To handle such special situations, use  mmc_last_cmd_key_asc_ascq(),
+     mmc_evaluate_sense_key_asc_ascq(), mmc_last_cmd_cdb(),
+     mmc_sense_code_to_text(), mmc_cdb_to_text().
+
+     @param report_mode
+              determines how dramatic at most detected problems shall be
+              reported:
+              CDIO_MMC_EVAL_SENSE_SILENT reports nothing
+              CDIO_MMC_EVAL_SENSE_DEBUG  reports >= CDIO_MMC_EVAL_SENSE_IGN
+                                         by cdio_debug()
+              CDIO_MMC_EVAL_SENSE_INFO   like CDIO_MMC_EVAL_SENSE_DEBUG but
+                                         reports by cdio_info()
+              CDIO_MMC_EVAL_SENSE_WARN   like CDIO_MMC_EVAL_SENSE_INFO but
+                                         reports > CDIO_MMC_EVAL_SENSE_IGN
+                                         by cdio_warn()
+              CDIO_MMC_EVAL_SENSE_ERROR  like CDIO_MMC_EVAL_SENSE_WARN but
+                                         reports > CDIO_MMC_EVAL_SENSE_IGN
+                                         by cdio_error()
+
+     @return  gives the evaluated severity:
+              CDIO_MMC_EVAL_SENSE_OK
+              CDIO_MMC_EVAL_SENSE_IGN
+              CDIO_MMC_EVAL_SENSE_RETRY
+              CDIO_MMC_EVAL_SENSE_FAIL,
+              CDIO_MMC_EVAL_SENSE_ABORT
+              See include/cdio/mmc_util.h
+  */
+  cdio_mmc_eval_sense_result_t mmc_evaluate_last_sense(
+               const CdIo_t *p_cdio, cdio_mmc_eval_sense_report_t report_mode);
+
+  /**
     Set the block size for subsequest read requests, via MMC.
   */
   driver_return_code_t mmc_set_blocksize ( const CdIo_t *p_cdio,
diff --git a/include/cdio/mmc_util.h b/include/cdio/mmc_util.h
index 980b448..7789217 100644
--- a/include/cdio/mmc_util.h
+++ b/include/cdio/mmc_util.h
@@ -32,6 +32,76 @@ extern "C" {
 #endif /* __cplusplus */
 
     /**
+        Convert a triple of key, asc, ascq into a human readable text, which
+        describes the meaning of these codes.
+
+        @param key, asc, ascq  give the input triple of error codes from
+                 sense data of an SCSI command.
+
+        @return  NULL if not enough memory is available. If not NULL it is a
+                 pointer to allocated human readable text which has to be
+                 disposed by cdio_free() when it is no longer needed.
+    */
+    char *mmc_sense_code_to_text(unsigned char key, unsigned char asc,
+                                 unsigned char ascq);
+
+    /**
+        Convert a MMC command into human readble text.
+
+        @param cdb      gives the MMC command to be converted to text.
+                        E.g. mmc_cdb_t.field
+        @param cdb_len  gives the number of valid bytes in cdb.
+                        Submit 0 to let mmc_get_cmd_len() deduce it.
+        @return         NULL if not enough memory is available or cdb_len was 0
+                        and could not be deduced from cdb. If not NULL it is a
+                        pointer to allocated human readable text which has to
+                        be disposed by cdio_free() when it is no longer needed.
+    */
+    char *mmc_cdb_to_text(uint8_t *cdb, int cdb_len);
+
+    /* Outcome of mmc_evaluate_sense_key_asc_ascq() :
+        CDIO_MMC_EVAL_SENSE_OK ..... No problem reported.
+        CDIO_MMC_EVAL_SENSE_IGN .... Problem which needs no direct reaction
+                                     (but it may predict particular future
+                                      failures if not proper action is taken).
+        CDIO_MMC_EVAL_SENSE_RETRY .. Desired action failed.
+                                     Retry may bring success (timeout or abort
+                                     due to repeated failure are responsibility
+                                     of the caller).
+        CDIO_MMC_EVAL_SENSE_FAIL ... Desired action failed.
+                                     Retry seems futile.
+        CDIO_MMC_EVAL_SENSE_ABORT .. Relation to drive is broken.
+       The values form an scale where higher numerical values mean more severe
+       sense codes than lower numerical values. (If a new severity class is
+       added, then it should be given the mean value of its neighbors.)
+    */
+    typedef enum {
+        CDIO_MMC_EVAL_SENSE_OK = 0,
+        CDIO_MMC_EVAL_SENSE_IGN = 10000,
+        CDIO_MMC_EVAL_SENSE_RETRY = 20000,
+        CDIO_MMC_EVAL_SENSE_FAIL = 30000,
+        CDIO_MMC_EVAL_SENSE_ABORT = 40000
+    } cdio_mmc_eval_sense_result_t;
+
+    /**
+       Evaluate the generic severity of an SCSI sense code.
+
+       The particular severity of a sense code in relation to the intention of
+       a particular SCSI command and its parameters can deviate from this
+       evaluation. E.g. it is no error if SBC command START/STOP UNIT with
+       Stop and Eject bit returns sense code
+          2 3A 02 MEDIUM NOT PRESENT  TRAY OPEN
+       but rather an explicit confirmation of success.
+
+       @return  gives the evaluated severity:
+                CDIO_MMC_EVAL_SENSE_OK, CDIO_MMC_EVAL_SENSE_IGN,
+                CDIO_MMC_EVAL_SENSE_RETRY, CDIO_MMC_EVAL_SENSE_FAIL,
+                CDIO_MMC_EVAL_SENSE_ABORT
+    */
+    cdio_mmc_eval_sense_result_t mmc_evaluate_sense_key_asc_ascq(
+                    unsigned char key, unsigned char asc, unsigned char ascq);
+
+    /**
        Profile profile codes used in GET_CONFIGURATION - PROFILE LIST. */
     typedef enum {
         CDIO_MMC_FEATURE_PROF_NON_REMOVABLE = 0x0001, /**< Re-writable disc, 
capable
diff --git a/lib/driver/FreeBSD/freebsd_cam.c b/lib/driver/FreeBSD/freebsd_cam.c
index 9eb6635..3601fc3 100644
--- a/lib/driver/FreeBSD/freebsd_cam.c
+++ b/lib/driver/FreeBSD/freebsd_cam.c
@@ -61,6 +61,8 @@ run_mmc_cmd_freebsd_cam( void *p_user_data, unsigned int 
i_timeout_ms,
   int direction = CAM_DEV_QFRZDIS | CAM_PASS_ERR_RECOVER;
   union ccb ccb;
 
+  p_env->gen.scsi_mmc_cdb_len = i_cdb;
+  memcpy(&(p_env->gen.scsi_mmc_cdb), p_cdb, sizeof(mmc_cdb_t));
   p_env->gen.scsi_mmc_sense_valid = 0;
   if (!p_env || !p_env->cam) return -2;
     
diff --git a/lib/driver/MSWindows/aspi32.c b/lib/driver/MSWindows/aspi32.c
index f8e94cf..dabc99b 100644
--- a/lib/driver/MSWindows/aspi32.c
+++ b/lib/driver/MSWindows/aspi32.c
@@ -504,6 +504,8 @@ run_mmc_cmd_aspi( void *p_user_data, unsigned int 
i_timeout_ms,
     return 1;
   }
   
+  p_env->gen.scsi_mmc_cdb_len = i_cdb;
+  memcpy(&(p_env->gen.scsi_mmc_cdb), p_cdb, sizeof(mmc_cdb_t));
   p_env->gen.scsi_mmc_sense_valid = 0;
   memset( &ssc, 0, sizeof( ssc ) );
 
diff --git a/lib/driver/MSWindows/win32_ioctl.c 
b/lib/driver/MSWindows/win32_ioctl.c
index 927bb1f..de2739e 100644
--- a/lib/driver/MSWindows/win32_ioctl.c
+++ b/lib/driver/MSWindows/win32_ioctl.c
@@ -486,6 +486,8 @@ run_mmc_cmd_win32ioctl( void *p_user_data,
   unsigned int u_swb_len =
     sizeof(SCSI_PASS_THROUGH_DIRECT_WITH_BUFFER);
 
+  p_env->gen.scsi_mmc_cdb_len = u_cdb;
+  memcpy(&(p_env->gen.scsi_mmc_cdb), p_cdb, sizeof(mmc_cdb_t));
   p_env->gen.scsi_mmc_sense_valid = 0;
   memset(&swb, 0, u_swb_len);
 
@@ -584,6 +586,8 @@ run_mmc_cmd_win32ioctl( void *p_user_data,
 
   p_sptwb = malloc(u_swb_len);
 
+  p_env->gen.scsi_mmc_cdb_len = u_cdb;
+  memcpy(&(p_env->gen.scsi_mmc_cdb), p_cdb, sizeof(mmc_cdb_t));
   p_env->gen.scsi_mmc_sense_valid = 0;
   memset(p_sptwb, 0, u_swb_len);
 
diff --git a/lib/driver/generic.h b/lib/driver/generic.h
index 8069ad5..8f014fb 100644
--- a/lib/driver/generic.h
+++ b/lib/driver/generic.h
@@ -69,10 +69,12 @@ extern "C" {
     cdtext_t *cdtext;       /**< CD-Text for disc. */
     track_flags_t track_flags[CDIO_CD_MAX_TRACKS+1];
 
-    /* Memorized sense reply of the most recent SCSI command.
+    /* Memorized most recent SCSI command and its sense data reply.
        Recorded by driver implementations of cdio_funcs_t.run_mmc_cmd().
-       Read by API function mmc_get_cmd_scsi_sense().
+       Read by API functions mmc_last_cmd_cdb() and mmc_last_cmd_sense().
     */
+    mmc_cdb_t scsi_mmc_cdb;
+    int scsi_mmc_cdb_len;
     unsigned char  scsi_mmc_sense[263];   /* See SPC-3 4.5.3 : 252 bytes legal
                                              but 263 bytes possible */
     int            scsi_mmc_sense_valid;  /* Number of valid sense bytes */
diff --git a/lib/driver/gnu_linux.c b/lib/driver/gnu_linux.c
index 107de88..e3c9b4a 100644
--- a/lib/driver/gnu_linux.c
+++ b/lib/driver/gnu_linux.c
@@ -514,6 +514,19 @@ get_media_changed_linux (const void *p_user_data) {
   string when done with it.
 
  */
+
+#define Libcdio_ts_mcn_via_mmC yes
+#ifdef Libcdio_ts_mcn_via_mmC
+
+static char *
+get_mcn_linux (const void *p_user_data) {
+
+  const _img_private_t *p_env = p_user_data;
+  return mmc_get_mcn( p_env->gen.cdio );
+}
+
+#else /* Libcdio_ts_mcn_via_mmC */
+
 static char *
 get_mcn_linux (const void *p_user_data) {
 
@@ -525,6 +538,8 @@ get_mcn_linux (const void *p_user_data) {
   return strdup((char *)mcn.medium_catalog_number);
 }
 
+#endif /* ! Libcdio_ts_mcn_via_mmC */
+
 /*!
   Return the international standard recording code ISRC.
 
@@ -1279,6 +1294,8 @@ run_mmc_cmd_linux(void *p_user_data,
   cdio_mmc_request_sense_t sense;
   unsigned char *u_sense = (unsigned char *) &sense;
 
+  p_env->gen.scsi_mmc_cdb_len = i_cdb;
+  memcpy(&(p_env->gen.scsi_mmc_cdb), p_cdb, sizeof(mmc_cdb_t));
   p_env->gen.scsi_mmc_sense_valid = 0;
   memset (&cgc, 0, sizeof (struct cdrom_generic_command));
   memcpy(&cgc.cmd, p_cdb, i_cdb);
diff --git a/lib/driver/mmc/mmc.c b/lib/driver/mmc/mmc.c
index fb85b8a..d07c570 100644
--- a/lib/driver/mmc/mmc.c
+++ b/lib/driver/mmc/mmc.c
@@ -551,6 +551,9 @@ mmc_get_mcn_isrc_private ( const CdIo_t *p_cdio,
   i_rc = mmc_read_subchannel (p_cdio, i_track,
                                    sub_chan_param, &num_data, buf, 0);
 
+  if (mmc_evaluate_last_sense(p_cdio, CDIO_MMC_EVAL_SENSE_WARN) >
+      CDIO_MMC_EVAL_SENSE_IGN)
+    return NULL;
   if (i_rc != DRIVER_OP_SUCCESS)
     return NULL;
 
@@ -562,6 +565,9 @@ mmc_get_mcn_isrc_private ( const CdIo_t *p_cdio,
 
   i_rc = mmc_read_subchannel (p_cdio, i_track,
                                    sub_chan_param, &num_data, buf, 0);
+  if (mmc_evaluate_last_sense(p_cdio, CDIO_MMC_EVAL_SENSE_WARN) >
+      CDIO_MMC_EVAL_SENSE_IGN)
+    return NULL;
   if (i_rc != DRIVER_OP_SUCCESS)
     return NULL;
 
@@ -1111,6 +1117,11 @@ char *
 mmc_get_track_isrc ( const CdIo_t *p_cdio, track_t i_track )
 {
   if ( ! p_cdio )  return NULL;
+
+  /* <<< ts B60531 To deliberately provoke a sense reply by wrong track number.
+  i_track = 4;
+ */
+
   return mmc_get_mcn_isrc_private (p_cdio, i_track, CDIO_SUBCHANNEL_TRACK_ISRC 
);
 }
 
@@ -1131,6 +1142,33 @@ int mmc_get_tray_status(const CdIo_t *p_cdio)
   return (status_buf[1] & 0x01) ? 1 : 0;
 }
 
+/**
+   Obtain a copy of the most-recently-performed MMC command bytes.
+
+   @param p_cdio    CD structure by which the MMC command was performed.
+   @param cdb       will in case of success point to a copy of the recorded
+                    CDB bytes. Dispose non-NULL pointers by cdio_free() when
+                    no longer needed.
+   @return          0 if no CDB is available.
+                    >0 gives the number of valid bytes in **cdb.
+*/
+int
+mmc_last_cmd_cdb(const CdIo_t *p_cdio, mmc_cdb_t **cdb)
+{
+    generic_img_private_t *gen;
+
+    if (!p_cdio) return DRIVER_OP_UNINIT;
+    gen = p_cdio->env;
+    *cdb = NULL;
+    if (gen->scsi_mmc_cdb_len <= 0)
+        return 0;
+    *cdb = calloc(1, sizeof(mmc_cdb_t));
+    if (*cdb == NULL)
+        return DRIVER_OP_ERROR;
+    memcpy(*cdb, &(gen->scsi_mmc_cdb), sizeof(mmc_cdb_t));
+    return gen->scsi_mmc_cdb_len;
+}
+
 /* Added in version 0.83 by scdbackup */
 /**
    Obtain the SCSI sense reply of the most-recently-performed MMC command.
@@ -1146,6 +1184,9 @@ int mmc_get_tray_status(const CdIo_t *p_cdio)
    codes as of SPC-3 Annex D, MMC-5 Annex F: sense[2]&15 = Key ,
    sense[12] = ASC , sense[13] = ASCQ
 
+   The layout of cdio_mmc_request_sense_t is valid only if the value of
+    cdio_mmc_request_sense_t.error_code  is 0x70 or 0x71.
+
    @return number of valid bytes in sense, 0 in case of no sense
    bytes available, <0 in case of internal error.
   */
@@ -1167,6 +1208,108 @@ mmc_last_cmd_sense(const CdIo_t *p_cdio, 
cdio_mmc_request_sense_t **pp_sense)
 }
 
 /**
+   Alternative to mmc_last_cmd_sense which can decode not only Fixed format
+   but also Descriptor format. The latter is not supposed to be issued by
+   MMC compliant drives. But it has been observed on Linux kernels with
+   key 0xB "Aborted command".
+*/
+int
+mmc_last_cmd_key_asc_ascq( const CdIo_t *p_cdio, unsigned char *key,
+                           unsigned char *asc, unsigned char *ascq)
+{
+    generic_img_private_t *gen;
+    int response_code;
+
+    if (!p_cdio) return DRIVER_OP_UNINIT;
+    gen = p_cdio->env;
+    if (gen->scsi_mmc_sense_valid <= 0)
+       return 0;
+    response_code = gen->scsi_mmc_sense[0] & 0x7f;
+    if (response_code == 0x70 || response_code == 0x71) {
+        /* Fixed format */
+        if (gen->scsi_mmc_sense_valid < 14)
+            return 0;
+        *key = gen->scsi_mmc_sense[2] & 0xf;
+        *asc = gen->scsi_mmc_sense[12];
+        *ascq = gen->scsi_mmc_sense[13];
+        return 1;
+    } else if (response_code == 0x72 || response_code == 0x73) {
+        /* Descriptor format */
+        if (gen->scsi_mmc_sense_valid < 4)
+            return 0;
+        *key = gen->scsi_mmc_sense[1] & 0xf;
+        *asc = gen->scsi_mmc_sense[2];
+        *ascq = gen->scsi_mmc_sense[3];
+        return 1;
+    }
+    return 0;
+}
+
+cdio_mmc_eval_sense_result_t
+mmc_evaluate_last_sense( const CdIo_t *p_cdio,
+                         cdio_mmc_eval_sense_report_t report_mode)
+{
+    int ret, cdb_len;
+    unsigned char key, asc, ascq;
+    cdio_mmc_eval_sense_result_t sev;
+    char *sense_text = NULL, *msg, *cdb_text = NULL;
+    mmc_cdb_t *cdb = NULL;
+
+    /* Evaluate */
+
+    ret = mmc_last_cmd_key_asc_ascq(p_cdio, &key, &asc, &ascq);
+    if (ret != 1)
+        return CDIO_MMC_EVAL_SENSE_IGN; /* unknown sense data format */
+    sev = mmc_evaluate_sense_key_asc_ascq(key, asc, ascq);
+
+    if (report_mode == CDIO_MMC_EVAL_SENSE_SILENT ||
+        sev == CDIO_MMC_EVAL_SENSE_OK)
+        return sev; /* Surely nothing to report */
+
+    /* Report
+      (from here on memory may get allocated which needs cdio_free()) */
+
+    cdb_len = mmc_last_cmd_cdb(p_cdio, &cdb);
+    if (cdb_len > 0 && cdb != NULL)
+        cdb_text = mmc_cdb_to_text(cdb->field, cdb_len);
+    else
+        cdb_text = NULL;
+    sense_text = mmc_sense_code_to_text(key, asc, ascq);
+    if (sense_text == NULL)
+        msg = (char *) "(- failed to format message text -)";
+    else
+        msg = sense_text;
+    if (report_mode >= CDIO_MMC_EVAL_SENSE_ERROR &&
+               sev > CDIO_MMC_EVAL_SENSE_IGN) {
+          if (cdb_text != NULL)
+              cdio_error("%s", cdb_text);
+          cdio_error("%s", msg);
+    } else if (report_mode >= CDIO_MMC_EVAL_SENSE_WARN &&
+               sev > CDIO_MMC_EVAL_SENSE_IGN) {
+          if (cdb_text != NULL)
+             cdio_warn("%s", cdb_text);
+          cdio_warn("%s", msg);
+    } else if (report_mode >= CDIO_MMC_EVAL_SENSE_INFO &&
+               sev >= CDIO_MMC_EVAL_SENSE_IGN) {
+          if (cdb_text != NULL)
+              cdio_info("%s", cdb_text);
+          cdio_info("%s", msg);
+    } else if (report_mode >= CDIO_MMC_EVAL_SENSE_DEBUG &&
+               sev >= CDIO_MMC_EVAL_SENSE_IGN) {
+          if (cdb_text != NULL)
+              cdio_debug("%s", cdb_text);
+          cdio_debug("%s", msg);
+    }
+    if (sense_text != NULL)
+        cdio_free(sense_text);
+    if (cdb_text != NULL)
+        cdio_free(cdb_text);
+    if (cdb != NULL)
+        cdio_free(cdb);
+    return sev;
+}
+
+/**
   Run a MMC command.
 
   @param cdio         CD structure set by cdio_open().
diff --git a/lib/driver/mmc/mmc_util.c b/lib/driver/mmc/mmc_util.c
index 99c68af..6039f80 100644
--- a/lib/driver/mmc/mmc_util.c
+++ b/lib/driver/mmc/mmc_util.c
@@ -26,6 +26,14 @@
 #include <stdio.h>
 #endif
 
+#ifdef HAVE_STRING_H
+#include <string.h>
+#endif
+
+#ifdef HAVE_STDLIB_H
+#include <stdlib.h>
+#endif
+
 #include <cdio/mmc.h>
 #include "mmc_private.h"
 
@@ -61,9 +69,9 @@ const char mmc_sense_key2str[16][40] = {
     "Copy aborted",          /**< A */
     "Aborted Command",       /**< B */
     "Obsolete",              /**< C */
-    "Unknown - 13",          /**< D */
-    "Unknown - 14",          /**< E */
-    "Unknown - 15",          /**< F */
+    "Unknown key 13",        /**< D */
+    "Unknown key 14",        /**< E */
+    "Unknown key 15",        /**< F */
 };
 
 /**
@@ -404,3 +412,408 @@ mmc_is_disctype_rewritable (cdio_mmc_feature_profile_t 
disctype) {
     }
 }
 
+
+/**
+ A single item of the translation list from ASC,ASCQ to text.
+*/
+struct mmc_asc_ascq_item {
+  unsigned short asc; /* 0x100 = end of list */
+  unsigned char  ascq;
+  const char *text;
+};
+
+/**
+ Sorted list of ASC, ASCQ error codes from SPC-3 and MMC-5.
+*/
+static struct mmc_asc_ascq_item mmc_asc_ascq_list[] = {
+  {0x00, 0x00, "(No additional sense information)"},
+  {0x00, 0x06, "I/O process terminated"},
+  {0x00, 0x16, "Operation in progress"},
+  {0x00, 0x17, "Cleaning requested"},
+  {0x02, 0x00, "No seek complete"},
+  {0x04, 0x00, "Logical unit not ready, cause not reportable"},
+  {0x04, 0x01, "Logical unit is in process of becoming ready"},
+  {0x04, 0x02, "Logical unit not ready, initializing cmd. required"},
+  {0x04, 0x03, "Logical unit not ready, manual intervention required"},
+  {0x04, 0x04, "Logical unit not ready, format in progress"},
+  {0x04, 0x07, "Logical unit not ready, operation in progress"},
+  {0x04, 0x08, "Logical unit not ready, long write in progress"},
+  {0x04, 0x09, "Logical unit not ready, self-test in progress"},
+  {0x05, 0x00, "Logical unit does not respond to selection"},
+  {0x06, 0x00, "No reference position found"},
+  {0x07, 0x00, "Multiple peripheral devices selected"},
+  {0x08, 0x00, "Logical unit communication failure"},
+  {0x08, 0x01, "Logical unit communication timeout"},
+  {0x08, 0x02, "Logical unit communication parity error"},
+  {0x08, 0x03, "Logical unit communication crc error (ultra-dma/32)"},
+  {0x09, 0x00, "Track following error"},
+  {0x09, 0x01, "Tracking servo failure"},
+  {0x09, 0x02, "Focus servo failure"},
+  {0x09, 0x03, "Spindle servo failure"},
+  {0x09, 0x04, "Head select fault"},
+  {0x0a, 0x00, "Error log overflow"},
+  {0x0b, 0x00, "Warning"},
+  {0x0b, 0x01, "Warning specified temperature exceeded"},
+  {0x0b, 0x02, "Warning enclosure degraded"},
+  {0x0b, 0x03, "Warning background self-test failed"},
+  {0x0b, 0x04, "Warning background pre-scan detected medium error"},
+  {0x0b, 0x05, "Warning background medium scan detected medium error"},
+  {0x0c, 0x00, "Write error"},
+  {0x0c, 0x01, "Write error recovered with auto-reallocation"},
+  {0x0c, 0x02, "Write error auto-reallocation failed"},
+  {0x0c, 0x03, "Write error recommend reassignment"},
+  {0x0c, 0x07, "Write error recovery needed"},
+  {0x0c, 0x08, "Write error recovery failed"},
+  {0x0c, 0x09, "Write error loss of streaming"},
+  {0x0c, 0x0a, "Write error padding blocks added"},
+  {0x0c, 0x0f, "Defects in error window"},
+  {0x11, 0x00, "Unrecovered read error"},
+  {0x11, 0x01, "Read retries exhausted"},
+  {0x11, 0x02, "Error too long to correct"},
+  {0x11, 0x05, "L-ec uncorrectable error"},
+  {0x11, 0x06, "Circ unrecovered error"},
+  {0x11, 0x0f, "Error reading upc/ean number"},
+  {0x11, 0x10, "Error reading isrc number"},
+  {0x11, 0x11, "Read error loss of streaming"},
+  {0x15, 0x00, "Random positioning error"},
+  {0x15, 0x01, "Mechanical positioning error"},
+  {0x15, 0x02, "Positioning error detected by read of medium"},
+  {0x17, 0x00, "Recovered data with no error correction applied"},
+  {0x17, 0x01, "Recovered data with retries"},
+  {0x17, 0x02, "Recovered data with positive head offset"},
+  {0x17, 0x03, "Recovered data with negative head offset"},
+  {0x17, 0x04, "Recovered data with retries and/or circ applied"},
+  {0x17, 0x05, "Recovered data using previous sector id"},
+  {0x17, 0x07, "Recovered data without ecc recommend reassignment"},
+  {0x17, 0x08, "Recovered data without ecc recommend rewrite"},
+  {0x17, 0x09, "Recovered data without ecc data rewritten"},
+  {0x18, 0x00, "Recovered data with error correction applied"},
+  {0x18, 0x01, "Recovered data with error corr. & retries applied"},
+  {0x18, 0x02, "Recovered data data auto-reallocated"},
+  {0x18, 0x03, "Recovered data with circ"},
+  {0x18, 0x04, "Recovered data with l-ec"},
+  {0x18, 0x05, "Recovered data recommend reassignment"},
+  {0x18, 0x06, "Recovered data recommend rewrite"},
+  {0x18, 0x08, "Recovered data with linking"},
+  {0x1a, 0x00, "Parameter list length error"},
+  {0x1b, 0x00, "Synchronous data transfer error"},
+  {0x1d, 0x00, "Miscompare during verify operation"},
+  {0x20, 0x00, "Invalid command operation code"},
+  {0x21, 0x00, "Logical block address out of range"},
+  {0x21, 0x01, "Invalid element address"},
+  {0x21, 0x02, "Invalid address for write"},
+  {0x21, 0x03, "Invalid write crossing layer jump"},
+  {0x22, 0x00, "Invalid function"},
+  {0x24, 0x00, "Invalid field in cdb"},
+  {0x25, 0x00, "Logical unit not supported"},
+  {0x26, 0x00, "Invalid field in parameter list"},
+  {0x26, 0x01, "Parameter not supported"},
+  {0x26, 0x02, "Parameter value invalid"},
+  {0x26, 0x03, "Threshold parameters not supported"},
+  {0x26, 0x04, "Invalid release of persistent reservation"},
+  {0x27, 0x00, "Write protected"},
+  {0x27, 0x01, "Hardware write protected"},
+  {0x27, 0x02, "Logical unit software write protected"},
+  {0x27, 0x03, "Associated write protect"},
+  {0x27, 0x04, "Persistent write protect"},
+  {0x27, 0x05, "Permanent write protect"},
+  {0x27, 0x06, "Conditional write protect"},
+  {0x28, 0x00, "Not ready to ready change, medium may have changed"},
+  {0x28, 0x01, "Import or export element accessed"},
+  {0x28, 0x02, "Format-layer may have changed"},
+  {0x29, 0x00, "Power on, reset, or bus device reset occurred"},
+  {0x29, 0x01, "Power on occurred"},
+  {0x29, 0x02, "Bus reset occurred"},
+  {0x29, 0x03, "Bus device reset function occurred"},
+  {0x29, 0x04, "Device internal reset"},
+  {0X2a, 0x00, "Parameters changed"},
+  {0x2a, 0x01, "Mode parameters changed"},
+  {0x2a, 0x02, "Log parameters changed"},
+  {0x2a, 0x03, "Reservations preempted"},
+  {0x2b, 0x00, "Copy cannot execute since initiator cannot disconnect"},
+  {0x2c, 0x00, "Command sequence error"},
+  {0x2c, 0x03, "Current program area is not empty"},
+  {0x2c, 0x04, "Current program area is empty"},
+  {0x2e, 0x00, "Insufficient time for operation"},
+  {0x2f, 0x00, "Commands cleared by another initiator"},
+  {0x30, 0x00, "Incompatible medium installed"},
+  {0x30, 0x01, "Cannot read medium unknown format"},
+  {0x30, 0x02, "Cannot read medium incompatible format"},
+  {0x30, 0x03, "Cleaning cartridge installed"},
+  {0x30, 0x04, "Cannot write medium unknown format"},
+  {0x30, 0x05, "Cannot write medium incompatible format"},
+  {0x30, 0x06, "Cannot format medium incompatible medium"},
+  {0x30, 0x07, "Cleaning failure"},
+  {0x30, 0x08, "Cannot write application code mismatch"},
+  {0x30, 0x09, "Current session not fixated for append"},
+  {0x30, 0x10, "Medium not formatted"},
+  {0x30, 0x11, "Cannot write medium unsupported medium version"},
+  {0x31, 0x00, "Medium format corrupted"},
+  {0x31, 0x01, "Format command failed"},
+  {0x31, 0x02, "Zoned formatting failed due to spare linking"},
+  {0x32, 0x00, "No defect spare location available"},
+  {0x34, 0x00, "Enclosure failure"},
+  {0x35, 0x00, "Enclosure services failure"},
+  {0x35, 0x01, "Unsupported enclosure function"},
+  {0x35, 0x02, "Enclosure services unavailable"},
+  {0x35, 0x03, "Enclosure services transfer failure"},
+  {0x35, 0x04, "Enclosure services transfer refused"},
+  {0x35, 0x04, "Rnclosure services transfer refused"},
+  {0x35, 0x05, "Enclosure services checksum error"},
+  {0x37, 0x00, "Rounded parameter"},
+  {0x39, 0x00, "Saving parameters not supported"},
+  {0x3a, 0x00, "Medium not present"},
+  {0x3a, 0x01, "Medium not present tray closed"},
+  {0x3a, 0x02, "Medium not present tray open"},
+  {0x3a, 0x03, "Medium not present loadable"},
+  {0x3b, 0x0d, "Medium destination element full"},
+  {0x3b, 0x0e, "Medium source element empty"},
+  {0x3b, 0x0f, "End of medium reached"},
+  {0x3b, 0x11, "Medium magazine not accessible"},
+  {0x3b, 0x12, "Medium magazine removed"},
+  {0x3b, 0x13, "Medium magazine inserted"},
+  {0x3b, 0x14, "Medium magazine locked"},
+  {0x3b, 0x15, "Medium magazine unlocked"},
+  {0x3b, 0x16, "Mechanical positioning or changer error"},
+  {0x3d, 0x00, "Invalid bits in identify message"},
+  {0x3e, 0x00, "Logical unit has not self-configured yet"},
+  {0x3e, 0x01, "Logical unit failure"},
+  {0x3e, 0x02, "Timeout on logical unit"},
+  {0x3f, 0x00, "Target operating conditions have changed"},
+  {0x3f, 0x01, "Microcode has been changed"},
+  {0x3f, 0x02, "Changed operating definition"},
+  {0x3f, 0x03, "Inquiry data has changed"},
+  {0x40, 0x00, "Diagnostic failure on component nn (80h-ffh)"},
+  {0x43, 0x00, "Message error"},
+  {0x44, 0x00, "Internal target failure"},
+  {0x45, 0x00, "Select or reselect failure"},
+  {0x46, 0x00, "Unsuccessful soft reset"},
+  {0x47, 0x00, "Scsi parity error"},
+  {0x48, 0x00, "Initiator detected error message received"},
+  {0x49, 0x00, "Invalid message error"},
+  {0x4a, 0x00, "Command phase error"},
+  {0x4b, 0x00, "Data phase error"},
+  {0x4c, 0x00, "Logical unit failed self-configuration"},
+  {0x4d, 0x00, "Tagged overlapped commands (nn = queue tag)"},
+  {0x4e, 0x00, "Overlapped commands attempted"},
+  {0x51, 0x00, "Erase failure"},
+  {0x51, 0x01, "Erase failure incomplete erase operation detected"},
+  {0x53, 0x00, "Media load or eject failed"},
+  {0x53, 0x02, "Medium removal prevented"},
+  {0x55, 0x00, "System resource failure"},
+  {0x57, 0x00, "Unable to recover table-of-contents"},
+  {0x5a, 0x00, "Operator request or state change input"},
+  {0x5a, 0x01, "Operator medium removal request"},
+  {0x5a, 0x02, "Operator selected write protect"},
+  {0x5a, 0x03, "Operator selected write permit"},
+  {0x5b, 0x00, "Log exception"},
+  {0x5b, 0x01, "Threshold condition met"},
+  {0x5b, 0x02, "Log counter at maximum"},
+  {0x5b, 0x03, "Log list codes exhausted"},
+  {0x5d, 0x00, "Failure prediction threshold exceeded"},
+  {0x5d, 0x01, "Media failure prediction threshold exceeded"},
+  {0x5d, 0x02, "Logical unit failure prediction threshold exceeded"},
+  {0x5d, 0x03, "Spare area exhaustion failure prediction threshold exceeded"},
+  {0x5d, 0xff, "Failure prediction threshold exceeded (false)"},
+  {0x5e, 0x00, "Low power condition on"},
+  {0x5e, 0x01, "Idle condition activated by timer"},
+  {0x5e, 0x02, "Standby condition activated by timer"},
+  {0x5e, 0x03, "Idle condition activated by command"},
+  {0x5e, 0x04, "Standby condition activated by command"},
+  {0x63, 0x00, "End of user area encountered on this track"},
+  {0x63, 0x01, "Packet does not fit in available space"},
+  {0x64, 0x00, "Illegal mode for this track"},
+  {0x64, 0x01, "Invalid packet size"},
+  {0x65, 0x00, "Voltage fault"},
+  {0x6f, 0x00, "Copy protection key exchange failure authentication failure"},
+  {0x6f, 0x01, "Copy protection key exchange failure key not present"},
+  {0x6f, 0x02, "Copy protection key exchange failure key not established"},
+  {0x6f, 0x03, "Read of scrambled sector without authentication"},
+  {0x6f, 0x04, "Media region code is mismatched to logical unit region"},
+  {0x6f, 0x05, "Logical unit region must be permanent/region reset count 
error"},
+  {0x6f, 0x06, "Insufficient block count for binding nonce recording"},
+  {0x6f, 0x07, "Conflict in binding nonce recording"},
+  {0x72, 0x00, "Session fixation error"},
+  {0x72, 0x01, "Session fixation error writing lead-in"},
+  {0x72, 0x02, "Session fixation error writing lead-out"},
+  {0x72, 0x03, "Session fixation error incomplete track in session"},
+  {0x72, 0x04, "Empty or partially written reserved track"},
+  {0x72, 0x05, "No more track reservations allowed"},
+  {0x72, 0x06, "RMZ extension is not allowed"},
+  {0x72, 0x07, "No more test zone extensions are allowed"},
+  {0x73, 0x00, "CD control error"},
+  {0x73, 0x01, "Power calibration area almost full"},
+  {0x73, 0x02, "Power calibration area is full"},
+  {0x73, 0x03, "Power calibration area error"},
+  {0x73, 0x04, "Program memory area update failure"},
+  {0x73, 0x05, "Program memory area is full"},
+  {0x73, 0x06, "RMA/PMA is almost full"},
+  {0x73, 0x10, "Current power calibration area is almost full"},
+  {0x73, 0x11, "Current power calibration area is full"},
+  {0x73, 0x17, "RDZ is full"},
+  {0x100, 0x00, "@EOL@"}
+};
+
+/**
+ Convert sense code triple key, asc, ascq into a human readable message.
+*/
+char *
+mmc_sense_code_to_text(unsigned char key, unsigned char asc,
+                       unsigned char ascq)
+{
+    int i, len;
+    const char *text = "";
+    char *reply;
+
+    /* Look for ASC, ASCQ text */
+    for(i = 0; mmc_asc_ascq_list[i].asc < 0x100; i++) {
+        if(mmc_asc_ascq_list[i].asc > asc)
+    break;
+        if(mmc_asc_ascq_list[i].asc == asc) {
+            if(text[0] == 0 || mmc_asc_ascq_list[i].ascq == ascq)
+                text = mmc_asc_ascq_list[i].text;
+            if(mmc_asc_ascq_list[i].ascq >= ascq)
+    break;
+        } 
+    }
+
+    /* Allocate and compose reply */
+    len = strlen("[X XX XX] : ");
+    len += strlen(mmc_sense_key2str[key & 0xf]) + 2;
+    if(text[0] == 0)
+        text = "(Unknown SCSI ASC error code)";
+    len += strlen(text);
+    reply= calloc(1, len + 1);
+    if(reply == NULL)
+        return NULL;
+    
+    sprintf(reply, "[%1.1X %2.2X %2.2X] : ", (unsigned int) key & 0xf, 
+            (unsigned int) asc & 0xff, (unsigned int) ascq & 0xff);
+    sprintf(reply + strlen(reply), "%s, ", mmc_sense_key2str[key & 0xf]);
+    strcat(reply, text);
+    return reply;
+}
+
+/**
+ Convert SCSI CDB bytes into a human readable message.
+*/
+char *
+mmc_cdb_to_text(uint8_t *cdb, int cdb_len)
+{
+    int l, i;
+    char *cdb_text;
+
+    if (cdb == NULL)
+        return NULL;
+    if (cdb_len <= 0)
+        cdb_len = mmc_get_cmd_len(cdb[0]);
+    if (cdb_len <= 0)
+        return NULL;  /* unknown command with no externally given length */
+
+    l = strlen(mmc_cmd2str(cdb[0])) + 6;
+    l += cdb_len * 3;
+    l += 2 + 1;
+    cdb_text = calloc(1, l);
+    if (cdb_text == NULL)
+        return NULL;
+
+    sprintf(cdb_text, "%s (CDB:", mmc_cmd2str(cdb[0]));
+    for (i = 0; i < cdb_len; i++)
+        sprintf(cdb_text + strlen(cdb_text), " %2.2X", (unsigned int) cdb[i]);
+    sprintf(cdb_text + strlen(cdb_text), " )");
+    return cdb_text;
+}
+
+/**
+   Evaluate the generic severity of an SCSI sense code.
+
+   The particular severity of a sense code in relation to the intention of
+   a particular SCSI command and its parameters can deviate from this
+   evaluation. E.g. it is no error if SBC command START/STOP UNIT with
+   Stop and Eject bit returns sense code
+      2 3A 02 MEDIUM NOT PRESENT  TRAY OPEN
+   but rather an explicit confirmation of success.
+
+   @return  gives the evaluated severity:
+            CDIO_MMC_EVAL_SENSE_OK, CDIO_MMC_EVAL_SENSE_IGN,
+            CDIO_MMC_EVAL_SENSE_RETRY, CDIO_MMC_EVAL_SENSE_FAIL,
+            CDIO_MMC_EVAL_SENSE_ABORT
+*/
+cdio_mmc_eval_sense_result_t
+mmc_evaluate_sense_key_asc_ascq( unsigned char key, unsigned char asc,
+                                 unsigned char ascq)
+{
+    if (key == 0x01)
+        return CDIO_MMC_EVAL_SENSE_IGN; /* Recovered error */
+
+    /* Not really sure whether this is the correct evaluation. A client as
+       clueless as me, the programmer, should best go on and see what happens.
+    */
+    if (key == 0x06)
+        return CDIO_MMC_EVAL_SENSE_IGN; /* Unit attention */
+
+    /* SPC-3 says that retry may recover. But all known occurences of key B
+       yielded an unusable drive connection.
+    */
+    if (key == 0x0b)
+        return CDIO_MMC_EVAL_SENSE_ABORT; /* Aborted command */
+
+    switch (asc) {
+    case 0x00:
+        if (key || ascq)
+            return CDIO_MMC_EVAL_SENSE_FAIL; /* (message meaning is obscure) */
+        return CDIO_MMC_EVAL_SENSE_OK;
+    case 0x02:
+        return CDIO_MMC_EVAL_SENSE_RETRY; /* No seek complete */
+    case 0x04:
+        return CDIO_MMC_EVAL_SENSE_RETRY; /* Logical unit not ready */
+    case 0x08:
+        return CDIO_MMC_EVAL_SENSE_RETRY; /* Logical unit communication
+                                             failure */
+    case 0x0b:
+        return CDIO_MMC_EVAL_SENSE_IGN; /* Warning */
+    case 0x0c:
+        if (ascq == 0x01)
+            return CDIO_MMC_EVAL_SENSE_IGN; /* Write error recovered with
+                                               auto-reallocation */
+        return CDIO_MMC_EVAL_SENSE_FAIL; /* Write error */
+    case 0x17:
+    case 0x18:
+        return CDIO_MMC_EVAL_SENSE_IGN; /* Recovered data
+                                           (really has two ASC numbers) */
+    case 0x25:
+        return CDIO_MMC_EVAL_SENSE_ABORT; /* Logical unit not supported */
+    case 0x28:
+        return CDIO_MMC_EVAL_SENSE_IGN; /* Medium related change */
+    case 0x29:
+        return CDIO_MMC_EVAL_SENSE_RETRY; /* Power on, reset, or bus device
+                                             reset */
+    case 0x5a:
+        return CDIO_MMC_EVAL_SENSE_IGN; /* Operator request or state change
+                                           input */
+    case 0x5e:
+        return CDIO_MMC_EVAL_SENSE_IGN; /* Power condition related change */
+    case 0x73:
+        if (ascq == 0x01)
+            return CDIO_MMC_EVAL_SENSE_IGN; /* Power calibration area almost
+                                               full */
+        if (ascq == 0x06)
+            return CDIO_MMC_EVAL_SENSE_IGN; /* RMA/PMA is almost full */
+        if (ascq == 0x10)
+            return CDIO_MMC_EVAL_SENSE_IGN; /* Current power calibration area
+                                               is almost full */
+        return CDIO_MMC_EVAL_SENSE_FAIL; /* Some important resource on medium
+                                            is full */
+
+    /* Yet unclear is the meaning of:
+       0x37 "Rounded parameter"
+            (is listed in specs with key 1 = Recovered Error)
+       0x3f "Target operating conditions have changed"
+            (key 6 = Unit attention)
+       Both keys currently return CDIO_MMC_EVAL_SENSE_IGN for all ASC.
+    */
+
+    }
+    return CDIO_MMC_EVAL_SENSE_FAIL; /* other problem */
+}
+ 
diff --git a/lib/driver/osx.c b/lib/driver/osx.c
index c361fd9..537c73b 100644
--- a/lib/driver/osx.c
+++ b/lib/driver/osx.c
@@ -439,6 +439,8 @@ run_mmc_cmd_osx( void *p_user_data,
 
   if (!p_env->scsi_task) return DRIVER_OP_UNSUPPORTED;
 
+  p_env->gen.scsi_mmc_cdb_len = i_cdb;
+  memcpy(&(p_env->gen.scsi_mmc_cdb), p_cdb, sizeof(mmc_cdb_t));
   p_env->gen.scsi_mmc_sense_valid = 0;
   memcpy(cmdbuf, p_cdb, i_cdb);
 
diff --git a/lib/driver/solaris.c b/lib/driver/solaris.c
index 0203bb3..666099e 100644
--- a/lib/driver/solaris.c
+++ b/lib/driver/solaris.c
@@ -363,13 +363,16 @@ run_mmc_cmd_solaris(void *p_user_data, unsigned int 
i_timeout_ms,
   cdio_mmc_request_sense_t sense;
   unsigned char *u_sense = (unsigned char *) &sense;
 
+  p_env->gen.scsi_mmc_cdb_len = i_cdb;
+  memcpy(&(p_env->gen.scsi_mmc_cdb), p_cdb, sizeof(mmc_cdb_t));
+  p_env->gen.scsi_mmc_sense_valid = 0;
+
   memset (&cgc, 0, sizeof (struct uscsi_cmd));
   cgc.uscsi_cdb = (caddr_t) p_cdb;
 
   /* See: man uscsi
           http://docs.sun.com/app/docs/doc/816-5177/uscsi-7i?a=view
   */
-  p_env->gen.scsi_mmc_sense_valid = 0;
   memset(u_sense, 0, sizeof(sense));
   cgc.uscsi_rqbuf = (caddr_t) u_sense;
   cgc.uscsi_rqlen = sizeof(sense); 

=========================================================================

Have a nice day :)

Thomas




reply via email to

[Prev in Thread] Current Thread [Next in Thread]