| Index: apps/diskmode/usb.c | 
| — | — | @@ -34,6 +34,7 @@ | 
| 35 | 35 | static union usb_endpoint_number usb_inep = { .number = 0, .direction = USB_ENDPOINT_DIRECTION_IN }; | 
| 36 | 36 | static int maxpacket = 512; | 
| 37 | 37 | static struct wakeup mainloop_wakeup; | 
|  | 38 | +static char* error = NULL; | 
| 38 | 39 |  | 
| 39 | 40 |  | 
| 40 | 41 | static const struct usb_devicedescriptor usb_devicedescriptor = | 
| — | — | @@ -204,7 +205,7 @@ | 
| 205 | 206 |  | 
| 206 | 207 | void handle_xfer_complete(const struct usb_instance* data, int ifnum, int epnum, int bytesleft) | 
| 207 | 208 | { | 
| 208 |  | -    ums_xfer_complete(epnum & 0x80, bytesleft);
 | 
|  | 209 | +    ums_xfer_complete(epnum, bytesleft); | 
| 209 | 210 | } | 
| 210 | 211 |  | 
| 211 | 212 |  | 
| — | — | @@ -234,7 +235,6 @@ | 
| 235 | 236 | static struct usb_endpoint usb_c1_i0_a0_ep1in = | 
| 236 | 237 | { | 
| 237 | 238 | .number = { .number = 0, .direction = USB_ENDPOINT_DIRECTION_IN }, | 
| 238 |  | -    .ctrl_request = handle_ep_ctrl_request,
 | 
| 239 | 239 | .xfer_complete = handle_xfer_complete, | 
| 240 | 240 | .timeout = handle_timeout, | 
| 241 | 241 | }; | 
| — | — | @@ -329,6 +329,8 @@ | 
| 330 | 330 | ums_handle_async(); | 
| 331 | 331 |  | 
| 332 | 332 | usbmanager_uninstall_custom(); | 
|  | 333 | + | 
|  | 334 | +    if (error) panic(PANIC_KILLTHREAD, error); | 
| 333 | 335 | } | 
| 334 | 336 |  | 
| 335 | 337 |  | 
| — | — | @@ -350,9 +352,21 @@ | 
| 351 | 353 | } | 
| 352 | 354 |  | 
| 353 | 355 |  | 
| 354 |  | -void usb_stall()
 | 
|  | 356 | +void usb_stall_in() | 
| 355 | 357 | { | 
| 356 |  | -    usb_set_stall(usb_handle, usb_outep, true);
 | 
| 357 | 358 | usb_set_stall(usb_handle, usb_inep, true); | 
| 358 | 359 | } | 
| 359 | 360 |  | 
|  | 361 | + | 
|  | 362 | +void usb_stall_out() | 
|  | 363 | +{ | 
|  | 364 | +    usb_set_stall(usb_handle, usb_outep, true); | 
|  | 365 | +} | 
|  | 366 | + | 
|  | 367 | + | 
|  | 368 | +void fail(char* errormsg) | 
|  | 369 | +{ | 
|  | 370 | +    error = errormsg; | 
|  | 371 | +    ums_ejected = true; | 
|  | 372 | +    wakeup_signal(&mainloop_wakeup); | 
|  | 373 | +} | 
| Index: apps/diskmode/usb.h | 
| — | — | @@ -36,7 +36,9 @@ | 
| 37 | 37 | extern void enqueue_async(); | 
| 38 | 38 | extern void usb_transmit(void* buffer, uint32_t len); | 
| 39 | 39 | extern void usb_receive(void* buffer, uint32_t len); | 
| 40 |  | -extern void usb_stall();
 | 
|  | 40 | +extern void usb_stall_in(); | 
|  | 41 | +extern void usb_stall_out(); | 
|  | 42 | +extern void fail(char* errormsg); | 
| 41 | 43 |  | 
| 42 | 44 | #endif | 
| 43 | 45 |  | 
| Index: apps/diskmode/ums.c | 
| — | — | @@ -26,6 +26,7 @@ | 
| 27 | 27 | #include "ums.h" | 
| 28 | 28 | #include "scsi.h" | 
| 29 | 29 | #include "usb.h" | 
|  | 30 | +#include "../../emcore/trunk/target/ipodclassic/storage_ata-target.h" | 
| 30 | 31 |  | 
| 31 | 32 |  | 
| 32 | 33 | #define UMS_BUFSIZE 65536 | 
| — | — | @@ -40,6 +41,8 @@ | 
| 41 | 42 | unsigned int tag; | 
| 42 | 43 | unsigned int lun; | 
| 43 | 44 | unsigned int last_result; | 
|  | 45 | +    unsigned int bytes_pending; | 
|  | 46 | +    bool data_direction; | 
| 44 | 47 | } cur_cmd; | 
| 45 | 48 |  | 
| 46 | 49 |  | 
| — | — | @@ -52,8 +55,38 @@ | 
| 53 | 56 | } cur_sense_data; | 
| 54 | 57 |  | 
| 55 | 58 |  | 
| 56 |  | -struct __attribute__((packed,aligned(32))) command_block_wrapper
 | 
|  | 59 | +static enum | 
| 57 | 60 | { | 
|  | 61 | +    SAT_PENDING_NONE = 0, | 
|  | 62 | +    SAT_PENDING_SRST, | 
|  | 63 | +    SAT_PENDING_HRST, | 
|  | 64 | +    SAT_PENDING_CMD, | 
|  | 65 | +    SAT_PENDING_READ_CDB, | 
|  | 66 | +} sat_pending = SAT_PENDING_NONE; | 
|  | 67 | +static struct ata_raw_cmd_t sat_command; | 
|  | 68 | +static struct __attribute__((packed)) sat_response_information | 
|  | 69 | +{ | 
|  | 70 | +    uint8_t descriptor_code; | 
|  | 71 | +    uint8_t additional_length; | 
|  | 72 | +    uint8_t extend; | 
|  | 73 | +    uint8_t error; | 
|  | 74 | +    uint8_t sector_count_h; | 
|  | 75 | +    uint8_t sector_count_l; | 
|  | 76 | +    uint8_t lba_low_h; | 
|  | 77 | +    uint8_t lba_low_l; | 
|  | 78 | +    uint8_t lba_mid_h; | 
|  | 79 | +    uint8_t lba_mid_l; | 
|  | 80 | +    uint8_t lba_high_h; | 
|  | 81 | +    uint8_t lba_high_l; | 
|  | 82 | +    uint8_t device; | 
|  | 83 | +    uint8_t status; | 
|  | 84 | +} sat_response_information; | 
|  | 85 | +static bool have_sat_response_information = false; | 
|  | 86 | +static bool sat_check; | 
|  | 87 | + | 
|  | 88 | + | 
|  | 89 | +struct __attribute__((packed)) command_block_wrapper | 
|  | 90 | +{ | 
| 58 | 91 | unsigned int signature; | 
| 59 | 92 | unsigned int tag; | 
| 60 | 93 | unsigned int data_transfer_length; | 
| — | — | @@ -78,7 +111,15 @@ | 
| 79 | 112 | struct inquiry_data inquiry; | 
| 80 | 113 | struct capacity capacity_data; | 
| 81 | 114 | struct format_capacity format_capacity_data; | 
| 82 |  | -    struct sense_data sense_data;
 | 
|  | 115 | +    struct sense_data_fixed sense_data_fixed; | 
|  | 116 | +    struct | 
|  | 117 | +    { | 
|  | 118 | +        struct sense_data_descr header; | 
|  | 119 | +        union | 
|  | 120 | +        { | 
|  | 121 | +            struct sat_response_information sat_response; | 
|  | 122 | +        } info; | 
|  | 123 | +    } sense_data_descr; | 
| 83 | 124 | struct mode_sense_data_6 ms_data_6; | 
| 84 | 125 | struct mode_sense_data_10 ms_data_10; | 
| 85 | 126 | struct report_lun_data lun_data; | 
| — | — | @@ -91,9 +132,10 @@ | 
| 92 | 133 | WAITING_FOR_COMMAND, | 
| 93 | 134 | SENDING_BLOCKS, | 
| 94 | 135 | SENDING_RESULT, | 
| 95 |  | -    SENDING_FAILED_RESULT,
 | 
| 96 | 136 | RECEIVING_BLOCKS, | 
| 97 |  | -    WAITING_FOR_CSW_COMPLETION
 | 
|  | 137 | +    WAITING_FOR_CSW_COMPLETION, | 
|  | 138 | +    RECEIVING_SAT_WRITE, | 
|  | 139 | +    PROCESSING, | 
| 98 | 140 | } state = WAITING_FOR_COMMAND; | 
| 99 | 141 |  | 
| 100 | 142 | static uint32_t length; | 
| — | — | @@ -135,9 +177,15 @@ | 
| 136 | 178 |  | 
| 137 | 179 | static void send_csw(int status) | 
| 138 | 180 | { | 
|  | 181 | +    if (cur_cmd.bytes_pending) | 
|  | 182 | +    { | 
|  | 183 | +        if (cur_cmd.data_direction) usb_stall_in(); | 
|  | 184 | +        else usb_stall_out(); | 
|  | 185 | +    } | 
|  | 186 | + | 
| 139 | 187 | tb.csw.signature = 0x53425355; | 
| 140 | 188 | tb.csw.tag = cur_cmd.tag; | 
| 141 |  | -    tb.csw.data_residue = 0;
 | 
|  | 189 | +    tb.csw.data_residue = cur_cmd.bytes_pending; | 
| 142 | 190 | tb.csw.status = status; | 
| 143 | 191 |  | 
| 144 | 192 | state = WAITING_FOR_CSW_COMPLETION; | 
| — | — | @@ -155,32 +203,66 @@ | 
| 156 | 204 |  | 
| 157 | 205 | static void receive_block_data(void* data, int size) | 
| 158 | 206 | { | 
| 159 |  | -    length = size;
 | 
| 160 |  | -    usb_receive(data, size);
 | 
| 161 |  | -    state = RECEIVING_BLOCKS;
 | 
|  | 207 | +    if (cur_cmd.data_direction) fail("diskmode: Attempting to receive data for IN command!"); | 
|  | 208 | +    else if (size > cur_cmd.bytes_pending) fail("diskmode: Receive overrun!"); | 
|  | 209 | +    else | 
|  | 210 | +    { | 
|  | 211 | +        cur_cmd.bytes_pending -= size; | 
|  | 212 | +        length = size; | 
|  | 213 | +        usb_receive(data, size); | 
|  | 214 | +        state = RECEIVING_BLOCKS; | 
|  | 215 | +    } | 
| 162 | 216 | } | 
| 163 | 217 |  | 
| 164 | 218 |  | 
|  | 219 | +static void receive_sat_write(void* data, int size) | 
|  | 220 | +{ | 
|  | 221 | +    if (cur_cmd.data_direction) fail("diskmode: Attempting to receive data for SAT IN command!"); | 
|  | 222 | +    else if (size > cur_cmd.bytes_pending) fail("diskmode: Receive SAT overrun!"); | 
|  | 223 | +    else | 
|  | 224 | +    { | 
|  | 225 | +        cur_cmd.bytes_pending -= size; | 
|  | 226 | +        length = size; | 
|  | 227 | +        usb_receive(data, size); | 
|  | 228 | +        state = RECEIVING_SAT_WRITE; | 
|  | 229 | +    } | 
|  | 230 | +} | 
|  | 231 | + | 
|  | 232 | + | 
| 165 | 233 | static void send_block_data(void* data, int size) | 
| 166 | 234 | { | 
| 167 |  | -    length = size;
 | 
| 168 |  | -    usb_transmit(data, size);
 | 
| 169 |  | -    state = SENDING_BLOCKS;
 | 
|  | 235 | +    if (!cur_cmd.data_direction) fail("diskmode: Attempting to send data for OUT command!"); | 
|  | 236 | +    else if (size > cur_cmd.bytes_pending) fail("diskmode: Send block overrun!"); | 
|  | 237 | +    else | 
|  | 238 | +    { | 
|  | 239 | +        cur_cmd.bytes_pending -= size; | 
|  | 240 | +        length = size; | 
|  | 241 | +        usb_transmit(data, size); | 
|  | 242 | +        state = SENDING_BLOCKS; | 
|  | 243 | +    } | 
| 170 | 244 | } | 
| 171 | 245 |  | 
| 172 | 246 |  | 
| 173 | 247 | static void send_command_result(void* data, int size) | 
| 174 | 248 | { | 
| 175 |  | -    length = size;
 | 
| 176 |  | -    usb_transmit(data, size);
 | 
| 177 |  | -    state = SENDING_RESULT;
 | 
|  | 249 | +    if (!cur_cmd.data_direction) fail("diskmode: Attempting to send result for OUT command!"); | 
|  | 250 | +    else if (size > cur_cmd.bytes_pending) fail("diskmode: Send result overrun!"); | 
|  | 251 | +    else | 
|  | 252 | +    { | 
|  | 253 | +        cur_cmd.bytes_pending -= size; | 
|  | 254 | +        length = size; | 
|  | 255 | +        usb_transmit(data, size); | 
|  | 256 | +        state = SENDING_RESULT; | 
|  | 257 | +    } | 
| 178 | 258 | } | 
| 179 | 259 |  | 
| 180 | 260 |  | 
| 181 |  | -static void send_command_failed_result()
 | 
|  | 261 | +static void send_command_failed_result(unsigned char key, unsigned char asc, unsigned char ascq) | 
| 182 | 262 | { | 
| 183 |  | -    usb_transmit(NULL, 0);
 | 
| 184 |  | -    state = SENDING_FAILED_RESULT;
 | 
|  | 263 | +    send_csw(1); | 
|  | 264 | +    cur_sense_data.sense_key = key; | 
|  | 265 | +    cur_sense_data.asc = asc; | 
|  | 266 | +    cur_sense_data.ascq = ascq; | 
| 185 | 267 | } | 
| 186 | 268 |  | 
| 187 | 269 |  | 
| — | — | @@ -255,24 +337,22 @@ | 
| 256 | 338 |  | 
| 257 | 339 | if (cbw->signature != 0x43425355) | 
| 258 | 340 | { | 
| 259 |  | -        usb_stall();
 | 
|  | 341 | +        usb_stall_in(); | 
|  | 342 | +        usb_stall_out(); | 
| 260 | 343 | return; | 
| 261 | 344 | } | 
| 262 | 345 | cur_cmd.tag = cbw->tag; | 
| 263 | 346 | cur_cmd.lun = cbw->lun; | 
| 264 | 347 | cur_cmd.cur_cmd = cbw->command_block[0]; | 
|  | 348 | +    cur_cmd.bytes_pending = cbw->data_transfer_length; | 
|  | 349 | +    if (cbw->flags & 0x80) cur_cmd.data_direction = 1; | 
|  | 350 | +    else cur_cmd.data_direction = 0; | 
| 265 | 351 |  | 
| 266 | 352 | switch (cbw->command_block[0]) | 
| 267 | 353 | { | 
| 268 | 354 | case SCSI_TEST_UNIT_READY: | 
| 269 | 355 | if (!ums_ejected) send_csw(0); | 
| 270 |  | -            else
 | 
| 271 |  | -            {
 | 
| 272 |  | -                send_csw(1);
 | 
| 273 |  | -                cur_sense_data.sense_key = SENSE_NOT_READY;
 | 
| 274 |  | -                cur_sense_data.asc = ASC_MEDIUM_NOT_PRESENT;
 | 
| 275 |  | -                cur_sense_data.ascq = 0;
 | 
| 276 |  | -            }
 | 
|  | 356 | +            else send_command_failed_result(SENSE_NOT_READY, ASC_MEDIUM_NOT_PRESENT, 0); | 
| 277 | 357 | break; | 
| 278 | 358 |  | 
| 279 | 359 | case SCSI_REPORT_LUNS: | 
| — | — | @@ -291,29 +371,40 @@ | 
| 292 | 372 |  | 
| 293 | 373 | case SCSI_REQUEST_SENSE: | 
| 294 | 374 | { | 
| 295 |  | -            tb.sense_data.ResponseCode = 0x70;
 | 
| 296 |  | -            tb.sense_data.Obsolete = 0;
 | 
| 297 |  | -            tb.sense_data.fei_sensekey = cur_sense_data.sense_key & 0x0f;
 | 
| 298 |  | -            tb.sense_data.Information = cur_sense_data.information;
 | 
| 299 |  | -            tb.sense_data.AdditionalSenseLength = 10;
 | 
| 300 |  | -            tb.sense_data.CommandSpecificInformation = 0;
 | 
| 301 |  | -            tb.sense_data.AdditionalSenseCode = cur_sense_data.asc;
 | 
| 302 |  | -            tb.sense_data.AdditionalSenseCodeQualifier = cur_sense_data.ascq;
 | 
| 303 |  | -            tb.sense_data.FieldReplaceableUnitCode = 0;
 | 
| 304 |  | -            tb.sense_data.SKSV = 0;
 | 
| 305 |  | -            tb.sense_data.SenseKeySpecific = 0;
 | 
| 306 |  | -            send_command_result(&tb.sense_data, MIN(sizeof(tb.sense_data), length));
 | 
|  | 375 | +            if (have_sat_response_information) | 
|  | 376 | +            { | 
|  | 377 | +                memset(&tb.sense_data_descr.header, 0, sizeof(tb.sense_data_descr.header)); | 
|  | 378 | +                tb.sense_data_descr.header.ResponseCode = 0x72; | 
|  | 379 | +                tb.sense_data_descr.header.fei_sensekey = cur_sense_data.sense_key & 0x0f; | 
|  | 380 | +                tb.sense_data_descr.header.AdditionalSenseCode = cur_sense_data.asc; | 
|  | 381 | +                tb.sense_data_descr.header.AdditionalSenseCodeQualifier = cur_sense_data.ascq; | 
|  | 382 | +                tb.sense_data_descr.header.AdditionalSenseLength = sizeof(sat_response_information); | 
|  | 383 | +                memcpy(&tb.sense_data_descr.info.sat_response, &sat_response_information, sizeof(sat_response_information)); | 
|  | 384 | +                send_command_result(&tb.sense_data_descr, MIN(sizeof(tb.sense_data_descr.header) + sizeof(sat_response_information), length)); | 
|  | 385 | +            } | 
|  | 386 | +            else | 
|  | 387 | +            { | 
|  | 388 | +                tb.sense_data_fixed.ResponseCode = 0x70; | 
|  | 389 | +                tb.sense_data_fixed.Obsolete = 0; | 
|  | 390 | +                tb.sense_data_fixed.fei_sensekey = cur_sense_data.sense_key & 0x0f; | 
|  | 391 | +                tb.sense_data_fixed.Information = cur_sense_data.information; | 
|  | 392 | +                tb.sense_data_fixed.AdditionalSenseLength = 10; | 
|  | 393 | +                tb.sense_data_fixed.CommandSpecificInformation = 0; | 
|  | 394 | +                tb.sense_data_fixed.AdditionalSenseCode = cur_sense_data.asc; | 
|  | 395 | +                tb.sense_data_fixed.AdditionalSenseCodeQualifier = cur_sense_data.ascq; | 
|  | 396 | +                tb.sense_data_fixed.FieldReplaceableUnitCode = 0; | 
|  | 397 | +                tb.sense_data_fixed.SKSV = 0; | 
|  | 398 | +                tb.sense_data_fixed.SenseKeySpecific = 0; | 
|  | 399 | +                send_command_result(&tb.sense_data_fixed, MIN(sizeof(tb.sense_data_fixed), length)); | 
|  | 400 | +            } | 
| 307 | 401 | break; | 
| 308 | 402 | } | 
| 309 | 403 |  | 
| 310 | 404 | case SCSI_MODE_SENSE_10: | 
| 311 | 405 | { | 
| 312 |  | -            if (ums_ejected)
 | 
|  | 406 | +            if (ums_ejected) | 
| 313 | 407 | { | 
| 314 |  | -                send_command_failed_result();
 | 
| 315 |  | -                cur_sense_data.sense_key = SENSE_NOT_READY;
 | 
| 316 |  | -                cur_sense_data.asc = ASC_MEDIUM_NOT_PRESENT;
 | 
| 317 |  | -                cur_sense_data.ascq = 0;
 | 
|  | 408 | +                send_command_failed_result(SENSE_NOT_READY, ASC_MEDIUM_NOT_PRESENT, 0); | 
| 318 | 409 | break; | 
| 319 | 410 | } | 
| 320 | 411 | unsigned char page_code = cbw->command_block[2] & 0x3f; | 
| — | — | @@ -342,10 +433,7 @@ | 
| 343 | 434 | send_command_result(&tb.ms_data_10, MIN(sizeof(tb.ms_data_10), length)); | 
| 344 | 435 | break; | 
| 345 | 436 | default: | 
| 346 |  | -                    send_command_failed_result();
 | 
| 347 |  | -                    cur_sense_data.sense_key = SENSE_ILLEGAL_REQUEST;
 | 
| 348 |  | -                    cur_sense_data.asc = ASC_INVALID_FIELD_IN_CBD;
 | 
| 349 |  | -                    cur_sense_data.ascq = 0;
 | 
|  | 437 | +                    send_command_failed_result(SENSE_ILLEGAL_REQUEST, ASC_INVALID_FIELD_IN_CBD, 0); | 
| 350 | 438 | break; | 
| 351 | 439 | } | 
| 352 | 440 | break; | 
| — | — | @@ -355,10 +443,7 @@ | 
| 356 | 444 | { | 
| 357 | 445 | if (ums_ejected) | 
| 358 | 446 | { | 
| 359 |  | -                send_command_failed_result();
 | 
| 360 |  | -                cur_sense_data.sense_key = SENSE_NOT_READY;
 | 
| 361 |  | -                cur_sense_data.asc = ASC_MEDIUM_NOT_PRESENT;
 | 
| 362 |  | -                cur_sense_data.ascq = 0;
 | 
|  | 447 | +                send_command_failed_result(SENSE_NOT_READY, ASC_MEDIUM_NOT_PRESENT, 0); | 
| 363 | 448 | break; | 
| 364 | 449 | } | 
| 365 | 450 | unsigned char page_code = cbw->command_block[2] & 0x3f; | 
| — | — | @@ -389,10 +474,7 @@ | 
| 390 | 475 | send_command_result(&tb.ms_data_6, MIN(sizeof(tb.ms_data_6), length)); | 
| 391 | 476 | break; | 
| 392 | 477 | default: | 
| 393 |  | -                    send_command_failed_result();
 | 
| 394 |  | -                    cur_sense_data.sense_key = SENSE_ILLEGAL_REQUEST;
 | 
| 395 |  | -                    cur_sense_data.asc = ASC_INVALID_FIELD_IN_CBD;
 | 
| 396 |  | -                    cur_sense_data.ascq = 0;
 | 
|  | 478 | +                    send_command_failed_result(SENSE_ILLEGAL_REQUEST, ASC_INVALID_FIELD_IN_CBD, 0); | 
| 397 | 479 | break; | 
| 398 | 480 | } | 
| 399 | 481 | break; | 
| — | — | @@ -419,13 +501,7 @@ | 
| 420 | 502 | tb.format_capacity_data.block_size |= swap32(SCSI_FORMAT_CAPACITY_FORMATTED_MEDIA); | 
| 421 | 503 | send_command_result(&tb.format_capacity_data, MIN(sizeof(tb.format_capacity_data), length)); | 
| 422 | 504 | } | 
| 423 |  | -           else
 | 
| 424 |  | -           {
 | 
| 425 |  | -               send_command_failed_result();
 | 
| 426 |  | -               cur_sense_data.sense_key = SENSE_NOT_READY;
 | 
| 427 |  | -               cur_sense_data.asc = ASC_MEDIUM_NOT_PRESENT;
 | 
| 428 |  | -               cur_sense_data.ascq = 0;
 | 
| 429 |  | -           }
 | 
|  | 505 | +           else send_command_failed_result(SENSE_NOT_READY, ASC_MEDIUM_NOT_PRESENT, 0); | 
| 430 | 506 | break; | 
| 431 | 507 | } | 
| 432 | 508 |  | 
| — | — | @@ -437,13 +513,7 @@ | 
| 438 | 514 | tb.capacity_data.block_size = swap32(storage_info.sector_size); | 
| 439 | 515 | send_command_result(&tb.capacity_data, MIN(sizeof(tb.capacity_data), length)); | 
| 440 | 516 | } | 
| 441 |  | -            else
 | 
| 442 |  | -            {
 | 
| 443 |  | -                send_command_failed_result();
 | 
| 444 |  | -                cur_sense_data.sense_key = SENSE_NOT_READY;
 | 
| 445 |  | -                cur_sense_data.asc = ASC_MEDIUM_NOT_PRESENT;
 | 
| 446 |  | -                cur_sense_data.ascq = 0;
 | 
| 447 |  | -            }
 | 
|  | 517 | +            else send_command_failed_result(SENSE_NOT_READY, ASC_MEDIUM_NOT_PRESENT, 0); | 
| 448 | 518 | break; | 
| 449 | 519 | } | 
| 450 | 520 |  | 
| — | — | @@ -450,10 +520,7 @@ | 
| 451 | 521 | case SCSI_READ_10: | 
| 452 | 522 | if (ums_ejected) | 
| 453 | 523 | { | 
| 454 |  | -                send_command_failed_result();
 | 
| 455 |  | -                cur_sense_data.sense_key = SENSE_NOT_READY;
 | 
| 456 |  | -                cur_sense_data.asc = ASC_MEDIUM_NOT_PRESENT;
 | 
| 457 |  | -                cur_sense_data.ascq = 0;
 | 
|  | 524 | +                send_command_failed_result(SENSE_NOT_READY, ASC_MEDIUM_NOT_PRESENT, 0); | 
| 458 | 525 | break; | 
| 459 | 526 | } | 
| 460 | 527 | cur_cmd.sector = (cbw->command_block[2] << 24 | cbw->command_block[3] << 16 | 
| — | — | @@ -462,12 +529,7 @@ | 
| 463 | 530 | cur_cmd.orig_count = cur_cmd.count; | 
| 464 | 531 |  | 
| 465 | 532 | if ((cur_cmd.sector + cur_cmd.count) > storage_info.num_sectors) | 
| 466 |  | -            {
 | 
| 467 |  | -                send_csw(1);
 | 
| 468 |  | -                cur_sense_data.sense_key = SENSE_ILLEGAL_REQUEST;
 | 
| 469 |  | -                cur_sense_data.asc = ASC_LBA_OUT_OF_RANGE;
 | 
| 470 |  | -                cur_sense_data.ascq = 0;
 | 
| 471 |  | -            }
 | 
|  | 533 | +                send_command_failed_result(SENSE_ILLEGAL_REQUEST, ASC_LBA_OUT_OF_RANGE, 0); | 
| 472 | 534 | else if (!cur_cmd.count) send_csw(0); | 
| 473 | 535 | else send_and_read_next(); | 
| 474 | 536 | break; | 
| — | — | @@ -475,10 +537,7 @@ | 
| 476 | 538 | case SCSI_WRITE_10: | 
| 477 | 539 | if (ums_ejected) | 
| 478 | 540 | { | 
| 479 |  | -                send_command_failed_result();
 | 
| 480 |  | -                cur_sense_data.sense_key = SENSE_NOT_READY;
 | 
| 481 |  | -                cur_sense_data.asc = ASC_MEDIUM_NOT_PRESENT;
 | 
| 482 |  | -                cur_sense_data.ascq = 0;
 | 
|  | 541 | +                send_command_failed_result(SENSE_NOT_READY, ASC_MEDIUM_NOT_PRESENT, 0); | 
| 483 | 542 | break; | 
| 484 | 543 | } | 
| 485 | 544 | cur_cmd.sector = (cbw->command_block[2] << 24 | cbw->command_block[3] << 16 | 
| — | — | @@ -487,12 +546,7 @@ | 
| 488 | 547 | cur_cmd.orig_count = cur_cmd.count; | 
| 489 | 548 |  | 
| 490 | 549 | if ((cur_cmd.sector + cur_cmd.count) > storage_info.num_sectors) | 
| 491 |  | -            {
 | 
| 492 |  | -                send_csw(1);
 | 
| 493 |  | -                cur_sense_data.sense_key = SENSE_ILLEGAL_REQUEST;
 | 
| 494 |  | -                cur_sense_data.asc = ASC_LBA_OUT_OF_RANGE;
 | 
| 495 |  | -                cur_sense_data.ascq = 0;
 | 
| 496 |  | -            }
 | 
|  | 550 | +                send_command_failed_result(SENSE_ILLEGAL_REQUEST, ASC_LBA_OUT_OF_RANGE, 0); | 
| 497 | 551 | else if (!cur_cmd.count) send_csw(0); | 
| 498 | 552 | else | 
| 499 | 553 | receive_block_data(umsbuf[1][!writebuf_current], | 
| — | — | @@ -501,14 +555,138 @@ | 
| 502 | 556 |  | 
| 503 | 557 | case SCSI_WRITE_BUFFER: | 
| 504 | 558 | break; | 
| 505 |  | -
 | 
|  | 559 | + | 
|  | 560 | +        case SCSI_ATA_PASSTHROUGH_12: | 
|  | 561 | +        case SCSI_ATA_PASSTHROUGH_16: | 
|  | 562 | +        { | 
|  | 563 | +            if (!storage_info.driverinfo || get_platform_id() != 0x4c435049) | 
|  | 564 | +            { | 
|  | 565 | +                send_command_failed_result(SENSE_ILLEGAL_REQUEST, ASC_INVALID_COMMAND, 0); | 
|  | 566 | +                break; | 
|  | 567 | +            } | 
|  | 568 | +            int cmd = cbw->command_block[0]; | 
|  | 569 | +            int multi = cbw->command_block[1] >> 5; | 
|  | 570 | +            int protocol = (cbw->command_block[1] >> 1) & 0xf; | 
|  | 571 | +            int extend = 0; | 
|  | 572 | +            int offline = cbw->command_block[2] >> 6; | 
|  | 573 | +            int check = (cbw->command_block[2] >> 5) & 1; | 
|  | 574 | +            int type = (cbw->command_block[2] >> 4) & 1; | 
|  | 575 | +            int dir = (cbw->command_block[2] >> 3) & 1; | 
|  | 576 | +            int block = (cbw->command_block[2] >> 2) & 1; | 
|  | 577 | +            int len = cbw->command_block[2] & 3; | 
|  | 578 | +            int features = cbw->command_block[3]; | 
|  | 579 | +            int count = cbw->command_block[4]; | 
|  | 580 | +            int lbal = cbw->command_block[5]; | 
|  | 581 | +            int lbam = cbw->command_block[6]; | 
|  | 582 | +            int lbah = cbw->command_block[7]; | 
|  | 583 | +            int device = cbw->command_block[8] & ~0x10; | 
|  | 584 | +            int command = cbw->command_block[9]; | 
|  | 585 | +            int control = cbw->command_block[11]; | 
|  | 586 | +            if (cmd == SCSI_ATA_PASSTHROUGH_16) | 
|  | 587 | +            { | 
|  | 588 | +                extend = cbw->command_block[1] & 1; | 
|  | 589 | +                features = (extend ? (cbw->command_block[3] << 8) : 0) | cbw->command_block[4]; | 
|  | 590 | +                count = (extend ? (cbw->command_block[5] << 8) : 0) | cbw->command_block[6]; | 
|  | 591 | +                lbal = (extend ? (cbw->command_block[7] << 8) : 0) | cbw->command_block[8]; | 
|  | 592 | +                lbam = (extend ? (cbw->command_block[9] << 8) : 0) | cbw->command_block[10]; | 
|  | 593 | +                lbah = (extend ? (cbw->command_block[11] << 8) : 0) | cbw->command_block[12]; | 
|  | 594 | +                device = cbw->command_block[13] & ~0x10; | 
|  | 595 | +                command = cbw->command_block[14]; | 
|  | 596 | +                control = cbw->command_block[15]; | 
|  | 597 | +            } | 
|  | 598 | +            sat_command.lba48 = extend; | 
|  | 599 | +            sat_check = check; | 
|  | 600 | +            int delay = (2 << offline) - 2; | 
|  | 601 | +            int bytes = 0; | 
|  | 602 | +            switch (len) | 
|  | 603 | +            { | 
|  | 604 | +                case 1: bytes = features; break; | 
|  | 605 | +                case 2: bytes = count; break; | 
|  | 606 | +                case 3: bytes = length; break; | 
|  | 607 | +            } | 
|  | 608 | +            int blocks = 1; | 
|  | 609 | +            if (block) | 
|  | 610 | +            { | 
|  | 611 | +                blocks = bytes; | 
|  | 612 | +                bytes = type ? storage_info.sector_size : 512; | 
|  | 613 | +            } | 
|  | 614 | +            int invalid = blocks * bytes > UMS_BUFSIZE; | 
|  | 615 | +            int dma = 0; | 
|  | 616 | +            switch (protocol) | 
|  | 617 | +            { | 
|  | 618 | +                case SAT_HARD_RESET: | 
|  | 619 | +                    sat_pending = SAT_PENDING_HRST; | 
|  | 620 | +                    enqueue_async(); | 
|  | 621 | +                    return; | 
|  | 622 | +                case SAT_SOFT_RESET: | 
|  | 623 | +                    sat_pending = SAT_PENDING_SRST; | 
|  | 624 | +                    enqueue_async(); | 
|  | 625 | +                    return; | 
|  | 626 | +                case SAT_NON_DATA: | 
|  | 627 | +                    if (len) invalid = 1; | 
|  | 628 | +                    break; | 
|  | 629 | +                case SAT_PIO_DATA_IN: | 
|  | 630 | +                    if (!len || !dir) invalid = 1; | 
|  | 631 | +                    break; | 
|  | 632 | +                case SAT_PIO_DATA_OUT: | 
|  | 633 | +                    if (!len || dir) invalid = 1; | 
|  | 634 | +                    break; | 
|  | 635 | +                case SAT_UDMA_DATA_IN: | 
|  | 636 | +                    if (!len || !dir) invalid = 1; | 
|  | 637 | +                    dma = 1; | 
|  | 638 | +                    break; | 
|  | 639 | +                case SAT_UDMA_DATA_OUT: | 
|  | 640 | +                    if (!len || dir) invalid = 1; | 
|  | 641 | +                    dma = 1; | 
|  | 642 | +                    break; | 
|  | 643 | +                case SAT_RETURN_RESPONSE: | 
|  | 644 | +                    sat_pending = SAT_PENDING_READ_CDB; | 
|  | 645 | +                    enqueue_async(); | 
|  | 646 | +                    return; | 
|  | 647 | +                //case SAT_NON_DATA_RESET: | 
|  | 648 | +                //case SAT_DMA: | 
|  | 649 | +                //case SAT_DMA_QUEUED: | 
|  | 650 | +                //case SAT_FPDMA: | 
|  | 651 | +                //case SAT_DIAGNOSTIC: | 
|  | 652 | +                default: | 
|  | 653 | +                    invalid = 1; | 
|  | 654 | +                    break; | 
|  | 655 | +            } | 
|  | 656 | +            if (invalid) | 
|  | 657 | +            { | 
|  | 658 | +                send_command_failed_result(SENSE_ILLEGAL_REQUEST, ASC_INVALID_FIELD_IN_CBD, 0); | 
|  | 659 | +                return; | 
|  | 660 | +            } | 
|  | 661 | +            readbuf_count[!readbuf_current] = 0; | 
|  | 662 | +            void* buffer = umsbuf[0][!readbuf_current]; | 
|  | 663 | +            sat_command.transfer = !!len; | 
|  | 664 | +            sat_command.send = !dir; | 
|  | 665 | +            sat_command.dma = dma; | 
|  | 666 | +            sat_command.delay = delay * 1000000; | 
|  | 667 | +            sat_command.buffer = buffer; | 
|  | 668 | +            sat_command.size = blocks; | 
|  | 669 | +            sat_command.blksize = bytes; | 
|  | 670 | +            sat_command.feature = features; | 
|  | 671 | +            sat_command.count = count; | 
|  | 672 | +            sat_command.lba_low = lbal; | 
|  | 673 | +            sat_command.lba_mid = lbam; | 
|  | 674 | +            sat_command.lba_high = lbah; | 
|  | 675 | +            sat_command.device = device; | 
|  | 676 | +            sat_command.command = command; | 
|  | 677 | +            if (len && !dir) receive_sat_write(buffer, bytes * blocks); | 
|  | 678 | +            else | 
|  | 679 | +            { | 
|  | 680 | +                sat_pending = SAT_PENDING_CMD; | 
|  | 681 | +                enqueue_async(); | 
|  | 682 | +            } | 
|  | 683 | +            break; | 
|  | 684 | +        } | 
|  | 685 | + | 
| 506 | 686 | default: | 
| 507 |  | -            send_csw(1);
 | 
| 508 |  | -            cur_sense_data.sense_key = SENSE_ILLEGAL_REQUEST;
 | 
| 509 |  | -            cur_sense_data.asc = ASC_INVALID_COMMAND;
 | 
| 510 |  | -            cur_sense_data.ascq = 0;
 | 
|  | 687 | +            send_command_failed_result(SENSE_ILLEGAL_REQUEST, ASC_INVALID_COMMAND, 0); | 
| 511 | 688 | break; | 
| 512 | 689 | } | 
|  | 690 | +    have_sat_response_information = false; | 
| 513 | 691 | } | 
| 514 | 692 |  | 
| 515 | 693 |  | 
| — | — | @@ -554,10 +732,8 @@ | 
| 555 | 733 | { | 
| 556 | 734 | if (IS_ERR(write_rc)) | 
| 557 | 735 | { | 
| 558 |  | -            send_csw(1);
 | 
| 559 |  | -            cur_sense_data.sense_key = SENSE_MEDIUM_ERROR;
 | 
| 560 |  | -            cur_sense_data.asc = ASC_WRITE_ERROR;
 | 
| 561 |  | -            cur_sense_data.ascq = 0;
 | 
|  | 736 | +            send_command_failed_result(SENSE_MEDIUM_ERROR, ASC_WRITE_ERROR, 0); | 
|  | 737 | +            return; | 
| 562 | 738 | } | 
| 563 | 739 | send_csw(0); | 
| 564 | 740 | write_rc = 0; | 
| — | — | @@ -569,34 +745,46 @@ | 
| 570 | 746 | void ums_xfer_complete(bool in, int bytesleft) | 
| 571 | 747 | { | 
| 572 | 748 | length -= bytesleft; | 
| 573 |  | -    switch (state)
 | 
| 574 |  | -    {
 | 
| 575 |  | -        case RECEIVING_BLOCKS:
 | 
| 576 |  | -            if (length != storage_info.sector_size * cur_cmd.count && length != UMS_BUFSIZE) break;
 | 
| 577 |  | -            update_readcache();
 | 
| 578 |  | -            if (!writebuf_busy) writebuf_push();
 | 
| 579 |  | -            else writebuf_overrun = true;
 | 
| 580 |  | -            enqueue_async();
 | 
| 581 |  | -            break;
 | 
| 582 |  | -        case WAITING_FOR_CSW_COMPLETION:
 | 
| 583 |  | -            state = WAITING_FOR_COMMAND;
 | 
| 584 |  | -            listen();
 | 
| 585 |  | -            break;
 | 
| 586 |  | -        case WAITING_FOR_COMMAND:
 | 
| 587 |  | -            invalidate_dcache(&cmdbuf, sizeof(cmdbuf));  // Who pulls this into a cache line!?
 | 
| 588 |  | -            handle_scsi(&cmdbuf.cbw);
 | 
| 589 |  | -            break;
 | 
| 590 |  | -        case SENDING_RESULT:
 | 
| 591 |  | -            send_csw(0);
 | 
| 592 |  | -            break;
 | 
| 593 |  | -        case SENDING_FAILED_RESULT:
 | 
| 594 |  | -            send_csw(1);
 | 
| 595 |  | -            break;
 | 
| 596 |  | -        case SENDING_BLOCKS:
 | 
| 597 |  | -            if (!cur_cmd.count) send_csw(0);
 | 
| 598 |  | -            else send_and_read_next();
 | 
| 599 |  | -            break;
 | 
| 600 |  | -    }
 | 
|  | 749 | +    if (in) | 
|  | 750 | +        switch (state) | 
|  | 751 | +        { | 
|  | 752 | +            case WAITING_FOR_CSW_COMPLETION: | 
|  | 753 | +                state = WAITING_FOR_COMMAND; | 
|  | 754 | +                listen(); | 
|  | 755 | +                break; | 
|  | 756 | +            case SENDING_RESULT: | 
|  | 757 | +                send_csw(0); | 
|  | 758 | +                break; | 
|  | 759 | +            case SENDING_BLOCKS: | 
|  | 760 | +                if (!cur_cmd.count) send_csw(0); | 
|  | 761 | +                else send_and_read_next(); | 
|  | 762 | +                break; | 
|  | 763 | +            default: | 
|  | 764 | +                fail("diskmode: Got IN completion in invalid state!"); | 
|  | 765 | +        } | 
|  | 766 | +    else | 
|  | 767 | +        switch (state) | 
|  | 768 | +        { | 
|  | 769 | +            case RECEIVING_BLOCKS: | 
|  | 770 | +                if (length != storage_info.sector_size * cur_cmd.count && length != UMS_BUFSIZE) break; | 
|  | 771 | +                update_readcache(); | 
|  | 772 | +                if (!writebuf_busy) writebuf_push(); | 
|  | 773 | +                else writebuf_overrun = true; | 
|  | 774 | +                enqueue_async(); | 
|  | 775 | +                break; | 
|  | 776 | +            case WAITING_FOR_COMMAND: | 
|  | 777 | +                state = PROCESSING; | 
|  | 778 | +                invalidate_dcache(&cmdbuf, sizeof(cmdbuf));  // Who pulls this into a cache line!? | 
|  | 779 | +                handle_scsi(&cmdbuf.cbw); | 
|  | 780 | +                break; | 
|  | 781 | +            case RECEIVING_SAT_WRITE: | 
|  | 782 | +                state = PROCESSING; | 
|  | 783 | +                sat_pending = SAT_PENDING_CMD; | 
|  | 784 | +                enqueue_async(); | 
|  | 785 | +                break; | 
|  | 786 | +            default: | 
|  | 787 | +                fail("diskmode: Got OUT completion in invalid state!"); | 
|  | 788 | +        } | 
| 601 | 789 | } | 
| 602 | 790 |  | 
| 603 | 791 | void ums_handle_async() | 
| — | — | @@ -625,13 +813,103 @@ | 
| 626 | 814 | { | 
| 627 | 815 | read_blocked = false; | 
| 628 | 816 | if (readbuf_count[readbuf_current] < 0) | 
|  | 817 | +            send_command_failed_result(SENSE_MEDIUM_ERROR, ASC_READ_ERROR, 0); | 
|  | 818 | +        else send_and_read_next(); | 
|  | 819 | +    } | 
|  | 820 | + | 
|  | 821 | +    struct ata_target_driverinfo* drv = storage_info.driverinfo; | 
|  | 822 | +    switch (sat_pending) | 
|  | 823 | +    { | 
|  | 824 | +        case SAT_PENDING_SRST: | 
| 629 | 825 | { | 
| 630 |  | -            send_csw(1);
 | 
| 631 |  | -            cur_sense_data.sense_key = SENSE_MEDIUM_ERROR;
 | 
| 632 |  | -            cur_sense_data.asc = ASC_READ_ERROR;
 | 
| 633 |  | -            cur_sense_data.ascq = 0;
 | 
|  | 826 | +            sat_pending = SAT_PENDING_NONE; | 
|  | 827 | +            if (IS_ERR(drv->soft_reset())) | 
|  | 828 | +                send_command_failed_result(SENSE_HARDWARE_ERROR, ASC_UNSUCCESSFUL_SOFT_RESET, 0); | 
|  | 829 | +            else send_csw(0); | 
|  | 830 | +            break; | 
| 634 | 831 | } | 
| 635 |  | -        else send_and_read_next();
 | 
|  | 832 | +        case SAT_PENDING_HRST: | 
|  | 833 | +        { | 
|  | 834 | +            sat_pending = SAT_PENDING_NONE; | 
|  | 835 | +            if (IS_ERR(drv->hard_reset())) | 
|  | 836 | +                send_command_failed_result(SENSE_HARDWARE_ERROR, ASC_UNSUCCESSFUL_SOFT_RESET, 0); | 
|  | 837 | +            else send_csw(0); | 
|  | 838 | +            break; | 
|  | 839 | +        } | 
|  | 840 | +        case SAT_PENDING_CMD: | 
|  | 841 | +        { | 
|  | 842 | +int cmd = sat_command.command; | 
|  | 843 | +            int datasize = sat_command.size * sat_command.blksize; | 
|  | 844 | +            void* buffer = sat_command.buffer; | 
|  | 845 | +            int rc = drv->raw_cmd(&sat_command); | 
|  | 846 | +            sat_response_information.descriptor_code = 9; | 
|  | 847 | +            sat_response_information.additional_length = 12; | 
|  | 848 | +            sat_response_information.extend = sat_command.lba48; | 
|  | 849 | +            sat_response_information.error = sat_command.feature; | 
|  | 850 | +            sat_response_information.sector_count_h = sat_command.count >> 8; | 
|  | 851 | +            sat_response_information.sector_count_l = sat_command.count & 0xff; | 
|  | 852 | +            sat_response_information.lba_low_h = sat_command.lba_low >> 8; | 
|  | 853 | +            sat_response_information.lba_low_l = sat_command.lba_low & 0xff; | 
|  | 854 | +            sat_response_information.lba_mid_h = sat_command.lba_mid >> 8; | 
|  | 855 | +            sat_response_information.lba_mid_l = sat_command.lba_mid & 0xff; | 
|  | 856 | +            sat_response_information.lba_high_h = sat_command.lba_high >> 8; | 
|  | 857 | +            sat_response_information.lba_high_l = sat_command.lba_high & 0xff; | 
|  | 858 | +            sat_response_information.device = sat_command.device; | 
|  | 859 | +            sat_response_information.status = sat_command.command; | 
|  | 860 | +            have_sat_response_information = true; | 
|  | 861 | +            sat_pending = SAT_PENDING_NONE; | 
|  | 862 | +            if (IS_ERR(rc) || (sat_command.command & 0x21)) | 
|  | 863 | +            { | 
|  | 864 | +                if (sat_command.command & 0x20) | 
|  | 865 | +                    send_command_failed_result(SENSE_HARDWARE_ERROR, ASC_INTERNAL_TARGET_FAILURE, 0); | 
|  | 866 | +                else if ((sat_command.command & 0x01) && (sat_command.feature & 0x01)) | 
|  | 867 | +                    send_command_failed_result(SENSE_MEDIUM_ERROR, ASC_ADDRESS_MARK_NOT_FOUND, 0); | 
|  | 868 | +                else if ((sat_command.command & 0x01) && (sat_command.feature & 0x02)) | 
|  | 869 | +                    send_command_failed_result(SENSE_NOT_READY, ASC_MEDIUM_NOT_PRESENT, 0); | 
|  | 870 | +                else if ((sat_command.command & 0x01) && (sat_command.feature & 0x08)) | 
|  | 871 | +                    send_command_failed_result(SENSE_UNIT_ATTENTION, ASC_OPERATOR_REQUEST, ASCQ_MEDIUM_REMOVAL_REQUEST); | 
|  | 872 | +                else if ((sat_command.command & 0x01) && (sat_command.feature & 0x10)) | 
|  | 873 | +                    send_command_failed_result(SENSE_ILLEGAL_REQUEST, ASC_LBA_OUT_OF_RANGE, 0); | 
|  | 874 | +                else if ((sat_command.command & 0x01) && (sat_command.feature & 0x20)) | 
|  | 875 | +                    send_command_failed_result(SENSE_UNIT_ATTENTION, ASC_MEDIUM_MAY_HAVE_CHANGED, 0); | 
|  | 876 | +                else if ((sat_command.command & 0x01) && (sat_command.feature & 0x40) && datasize && !sat_command.send) | 
|  | 877 | +                    send_command_failed_result(SENSE_MEDIUM_ERROR, ASC_READ_ERROR, 0); | 
|  | 878 | +                else if ((sat_command.command & 0x01) && (sat_command.feature & 0x40)) | 
|  | 879 | +                    send_command_failed_result(SENSE_DATA_PROTECT, ASC_WRITE_PROTECTED, 0); | 
|  | 880 | +                else if ((sat_command.command & 0x01) && (sat_command.feature & 0x80)) | 
|  | 881 | +                    send_command_failed_result(SENSE_ABORTED_COMMAND, ASC_SCSI_PARITY_ERROR, ASCQ_UICRC_ERROR_DETECTED); | 
|  | 882 | +                else if ((sat_command.command & 0x01) && (sat_command.feature & 0x04)) | 
|  | 883 | +                    send_command_failed_result(SENSE_ABORTED_COMMAND, 0, 0); | 
|  | 884 | +                else send_command_failed_result(SENSE_HARDWARE_ERROR, ASC_INTERNAL_TARGET_FAILURE, 0); | 
|  | 885 | +            } | 
|  | 886 | +            else if (sat_check) | 
|  | 887 | +                send_command_failed_result(SENSE_SOFT_ERROR, ASC_RECOVERED_ERROR, ASCQ_SAT_INFO_AVAILABLE); | 
|  | 888 | +            else if (datasize) send_command_result(buffer, datasize); | 
|  | 889 | +            else send_csw(0); | 
|  | 890 | +            break; | 
|  | 891 | +        } | 
|  | 892 | +        case SAT_PENDING_READ_CDB: | 
|  | 893 | +        { | 
|  | 894 | +            int rc = drv->read_taskfile(&sat_command); | 
|  | 895 | +            sat_response_information.descriptor_code = 9; | 
|  | 896 | +            sat_response_information.additional_length = 12; | 
|  | 897 | +            sat_response_information.extend = sat_command.lba48; | 
|  | 898 | +            sat_response_information.error = sat_command.feature; | 
|  | 899 | +            sat_response_information.sector_count_h = sat_command.count >> 8; | 
|  | 900 | +            sat_response_information.sector_count_l = sat_command.count & 0xff; | 
|  | 901 | +            sat_response_information.lba_low_h = sat_command.lba_low >> 8; | 
|  | 902 | +            sat_response_information.lba_low_l = sat_command.lba_low & 0xff; | 
|  | 903 | +            sat_response_information.lba_mid_h = sat_command.lba_mid >> 8; | 
|  | 904 | +            sat_response_information.lba_mid_l = sat_command.lba_mid & 0xff; | 
|  | 905 | +            sat_response_information.lba_high_h = sat_command.lba_high >> 8; | 
|  | 906 | +            sat_response_information.lba_high_l = sat_command.lba_high & 0xff; | 
|  | 907 | +            sat_response_information.device = sat_command.device; | 
|  | 908 | +            sat_response_information.status = sat_command.command; | 
|  | 909 | +            sat_pending = SAT_PENDING_NONE; | 
|  | 910 | +            if (IS_ERR(rc)) send_command_failed_result(SENSE_HARDWARE_ERROR, ASC_INTERNAL_TARGET_FAILURE, 0); | 
|  | 911 | +            else send_command_result(&sat_response_information, sizeof(sat_response_information)); | 
|  | 912 | +            break; | 
|  | 913 | +        } | 
| 636 | 914 | } | 
| 637 | 915 | } | 
| 638 | 916 |  | 
| Index: apps/diskmode/scsi.h | 
| — | — | @@ -41,11 +41,17 @@ | 
| 42 | 42 | #define SCSI_START_STOP_UNIT        0x1b | 
| 43 | 43 | #define SCSI_REPORT_LUNS            0xa0 | 
| 44 | 44 | #define SCSI_WRITE_BUFFER           0x3b | 
|  | 45 | +#define SCSI_ATA_PASSTHROUGH_12     0xa1 | 
|  | 46 | +#define SCSI_ATA_PASSTHROUGH_16     0x85 | 
| 45 | 47 |  | 
|  | 48 | +#define SENSE_SOFT_ERROR            0x01 | 
| 46 | 49 | #define SENSE_NOT_READY             0x02 | 
| 47 | 50 | #define SENSE_MEDIUM_ERROR          0x03 | 
|  | 51 | +#define SENSE_HARDWARE_ERROR        0x04 | 
| 48 | 52 | #define SENSE_ILLEGAL_REQUEST       0x05 | 
| 49 | 53 | #define SENSE_UNIT_ATTENTION        0x06 | 
|  | 54 | +#define SENSE_DATA_PROTECT          0x07 | 
|  | 55 | +#define SENSE_ABORTED_COMMAND       0x0b | 
| 50 | 56 |  | 
| 51 | 57 | #define ASC_MEDIUM_NOT_PRESENT      0x3a | 
| 52 | 58 | #define ASC_INVALID_FIELD_IN_CBD    0x24 | 
| — | — | @@ -54,9 +60,34 @@ | 
| 55 | 61 | #define ASC_READ_ERROR              0x11 | 
| 56 | 62 | #define ASC_NOT_READY               0x04 | 
| 57 | 63 | #define ASC_INVALID_COMMAND         0x20 | 
|  | 64 | +#define ASC_INTERNAL_TARGET_FAILURE 0x44 | 
|  | 65 | +#define ASC_ADDRESS_MARK_NOT_FOUND  0x13 | 
|  | 66 | +#define ASC_OPERATOR_REQUEST        0x5a | 
|  | 67 | +#define ASC_MEDIUM_MAY_HAVE_CHANGED 0x28 | 
|  | 68 | +#define ASC_SCSI_PARITY_ERROR       0x47 | 
|  | 69 | +#define ASC_WRITE_PROTECTED         0x27 | 
|  | 70 | +#define ASC_RECOVERED_ERROR         0x00 | 
|  | 71 | +#define ASC_UNSUCCESSFUL_SOFT_RESET 0x46 | 
| 58 | 72 |  | 
| 59 | 73 | #define ASCQ_BECOMING_READY         0x01 | 
|  | 74 | +#define ASCQ_MEDIUM_REMOVAL_REQUEST 0x01 | 
|  | 75 | +#define ASCQ_UICRC_ERROR_DETECTED   0x03 | 
|  | 76 | +#define ASCQ_SAT_INFO_AVAILABLE     0x1d | 
| 60 | 77 |  | 
|  | 78 | +#define SAT_HARD_RESET              0x0 | 
|  | 79 | +#define SAT_SOFT_RESET              0x1 | 
|  | 80 | +#define SAT_NON_DATA                0x3 | 
|  | 81 | +#define SAT_PIO_DATA_IN             0x4 | 
|  | 82 | +#define SAT_PIO_DATA_OUT            0x5 | 
|  | 83 | +#define SAT_DMA                     0x6 | 
|  | 84 | +#define SAT_DMA_QUEUED              0x7 | 
|  | 85 | +#define SAT_DIAGNOSTIC              0x8 | 
|  | 86 | +#define SAT_NON_DATA_RESET          0x9 | 
|  | 87 | +#define SAT_UDMA_DATA_IN            0xa | 
|  | 88 | +#define SAT_UDMA_DATA_OUT           0xb | 
|  | 89 | +#define SAT_FPDMA                   0xc | 
|  | 90 | +#define SAT_RETURN_RESPONSE         0xf | 
|  | 91 | + | 
| 61 | 92 | #define DIRECT_ACCESS_DEVICE        0x00 | 
| 62 | 93 | #define DEVICE_REMOVABLE            0x80 | 
| 63 | 94 |  | 
| — | — | @@ -84,7 +115,7 @@ | 
| 85 | 116 | unsigned char luns[1][8]; | 
| 86 | 117 | }; | 
| 87 | 118 |  | 
| 88 |  | -struct __attribute__((packed)) sense_data
 | 
|  | 119 | +struct __attribute__((packed)) sense_data_fixed | 
| 89 | 120 | { | 
| 90 | 121 | unsigned char ResponseCode; | 
| 91 | 122 | unsigned char Obsolete; | 
| — | — | @@ -99,6 +130,16 @@ | 
| 100 | 131 | unsigned short SenseKeySpecific; | 
| 101 | 132 | }; | 
| 102 | 133 |  | 
|  | 134 | +struct __attribute__((packed)) sense_data_descr | 
|  | 135 | +{ | 
|  | 136 | +    unsigned char ResponseCode; | 
|  | 137 | +    unsigned char fei_sensekey; | 
|  | 138 | +    unsigned char AdditionalSenseCode; | 
|  | 139 | +    unsigned char AdditionalSenseCodeQualifier; | 
|  | 140 | +    unsigned char Reserved[3]; | 
|  | 141 | +    unsigned char AdditionalSenseLength; | 
|  | 142 | +}; | 
|  | 143 | + | 
| 103 | 144 | struct __attribute__((packed)) mode_sense_bdesc_longlba | 
| 104 | 145 | { | 
| 105 | 146 | unsigned char num_blocks[8]; |