/*!
    \file    usbd_msc_scsi.h
    \brief   the header file of the usbd_msc_scsi.c file

    \version 2020-08-01, V3.0.0, firmware for GD32F30x
    \version 2021-02-20, V3.0.1, firmware for GD32F30x
    \version 2022-06-10, V3.1.0, firmware for GD32F30x
*/

/*
    Copyright (c) 2022, GigaDevice Semiconductor Inc.

    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 copyright holder 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 HOLDER 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 __USBD_MSC_SCSI_H
#define __USBD_MSC_SCSI_H

#include "usbd_msc_bbb.h"

#define SENSE_LIST_DEEPTH                           4U

/* SCSI commands */
#define SCSI_FORMAT_UNIT                            0x04U
#define SCSI_INQUIRY                                0x12U
#define SCSI_MODE_SELECT6                           0x15U
#define SCSI_MODE_SELECT10                          0x55U
#define SCSI_MODE_SENSE6                            0x1AU
#define SCSI_READ_TOC_DATA                          0x43U
#define SCSI_MODE_SENSE10                           0x5AU
#define SCSI_ALLOW_MEDIUM_REMOVAL                   0x1EU
#define SCSI_READ6                                  0x08U
#define SCSI_READ10                                 0x28U
#define SCSI_READ12                                 0xA8U
#define SCSI_READ16                                 0x88U

#define SCSI_READ_CAPACITY10                        0x25U
#define SCSI_READ_CAPACITY16                        0x9EU

#define SCSI_REQUEST_SENSE                          0x03U
#define SCSI_START_STOP_UNIT                        0x1BU
#define SCSI_TEST_UNIT_READY                        0x00U
#define SCSI_WRITE6                                 0x0AU
#define SCSI_WRITE10                                0x2AU
#define SCSI_WRITE12                                0xAAU
#define SCSI_WRITE16                                0x8AU

#define SCSI_VERIFY10                               0x2FU
#define SCSI_VERIFY12                               0xAFU
#define SCSI_VERIFY16                               0x8FU

#define SCSI_SEND_DIAGNOSTIC                        0x1DU
#define SCSI_READ_FORMAT_CAPACITIES                 0x23U

#define INVALID_CDB                                 0x20U
#define INVALID_FIELED_IN_COMMAND                   0x24U
#define PARAMETER_LIST_LENGTH_ERROR                 0x1AU
#define INVALID_FIELD_IN_PARAMETER_LIST             0x26U
#define ADDRESS_OUT_OF_RANGE                        0x21U
#define MEDIUM_NOT_PRESENT                          0x3AU
#define MEDIUM_HAVE_CHANGED                         0x28U
#define WRITE_PROTECTED                             0x27U
#define UNRECOVERED_READ_ERROR                      0x11U
#define WRITE_FAULT                                 0x03U

#define READ_FORMAT_CAPACITY_DATA_LEN               0x0CU
#define READ_CAPACITY10_DATA_LEN                    0x08U
#define MODE_SENSE10_DATA_LEN                       0x08U
#define MODE_SENSE6_DATA_LEN                        0x04U
#define READ_TOC_CMD_LEN                            0x14U
#define REQUEST_SENSE_DATA_LEN                      0x12U
#define STANDARD_INQUIRY_DATA_LEN                   0x24U
#define BLKVFY                                      0x04U

#define MODE_SENSE6_LENGTH                          8U
#define MODE_SENSE10_LENGTH                         8U
#define INQUIRY_PAGE00_LENGTH                       96U
#define FORMAT_CAPACITIES_LENGTH                    20U

enum sense_state 
{
    NO_SENSE = 0U,
    RECOVERED_ERROR,
    NOT_READY,
    MEDIUM_ERROR,
    HARDWARE_ERROR,
    ILLEGAL_REQUEST,
    UNIT_ATTENTION,
    DATA_PROTECT,
    BLANK_CHECK,
    VENDOR_SPECIFIC,
    COPY_ABORTED,
    ABORTED_COMMAND,
    RESERVED,
    VOLUME_OVERFLOW,
    MISCOMPARE
};

typedef struct {
    uint8_t  SenseKey;
    uint32_t Information;
    uint8_t  ASC;
    uint8_t  ASCQ;
} msc_scsi_sense;

extern const uint8_t msc_page00_inquiry_data[];
extern const uint8_t msc_mode_sense6_data[];
extern const uint8_t msc_mode_sense10_data[];

/* function declarations */
/* process SCSI commands */
int8_t scsi_process_cmd (usb_dev *udev, uint8_t lun, uint8_t *cmd);
/* load the last error code in the error list */
void scsi_sense_code (usb_dev *udev, uint8_t lun, uint8_t skey, uint8_t asc);

#endif /* __USBD_MSC_SCSI_H */
